diff --git a/packages/buttons/package.json b/packages/buttons/package.json
index a0c7602c..56b5c081 100644
--- a/packages/buttons/package.json
+++ b/packages/buttons/package.json
@@ -36,7 +36,7 @@
"@types/ember": "^3.1.2",
"@types/ember-qunit": "^3.4.8",
"@types/ember__test-helpers": "^0.7.10",
- "@types/qunit": "^2.9.0",
+ "@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
"autoprefixer": "^9.7.5",
"broccoli-asset-rev": "^3.0.0",
@@ -52,7 +52,7 @@
"ember-maybe-import-regenerator": "^0.1.6",
"ember-qunit": "^4.6.0",
"ember-resolver": "^7.0.0",
- "ember-source": "~3.17.2",
+ "ember-source": "~3.17.3",
"ember-try": "^1.4.0",
"loader.js": "^4.7.0",
"qunit-dom": "^1.1.0",
diff --git a/packages/changeset-form/package.json b/packages/changeset-form/package.json
index 7e0e8db0..4321db43 100644
--- a/packages/changeset-form/package.json
+++ b/packages/changeset-form/package.json
@@ -38,7 +38,7 @@
"@types/ember": "^3.1.2",
"@types/ember-qunit": "^3.4.8",
"@types/ember__test-helpers": "^0.7.10",
- "@types/qunit": "^2.9.0",
+ "@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
"autoprefixer": "^9.7.5",
"broccoli-asset-rev": "^3.0.0",
@@ -54,7 +54,7 @@
"ember-maybe-import-regenerator": "^0.1.6",
"ember-qunit": "^4.6.0",
"ember-resolver": "^7.0.0",
- "ember-source": "~3.17.2",
+ "ember-source": "~3.17.3",
"ember-try": "^1.4.0",
"loader.js": "^4.7.0",
"qunit-dom": "^1.1.0",
diff --git a/packages/core/package.json b/packages/core/package.json
index 40ffa775..9e24a789 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -27,7 +27,7 @@
"ember-cli-babel": "^7.19.0",
"ember-cli-htmlbars": "^4.2.3",
"ember-cli-typescript": "^3.1.3",
- "focus-visible": "^5.0.2"
+ "focus-visible": "^5.1.0"
},
"devDependencies": {
"@babel/core": "^7.9.0",
@@ -37,7 +37,7 @@
"@types/ember": "^3.1.2",
"@types/ember-qunit": "^3.4.8",
"@types/ember__test-helpers": "^0.7.10",
- "@types/qunit": "^2.9.0",
+ "@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
"broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.3.0",
@@ -51,7 +51,7 @@
"ember-maybe-import-regenerator": "^0.1.6",
"ember-qunit": "^4.4.1",
"ember-resolver": "^7.0.0",
- "ember-source": "^3.17.2",
+ "ember-source": "^3.17.3",
"ember-try": "^1.2.1",
"loader.js": "^4.7.0",
"qunit-dom": "^1.1.0",
diff --git a/packages/docs/app/components/demo/overlays/demo-modal.hbs b/packages/docs/app/components/demo/overlays/demo-modal.hbs
new file mode 100644
index 00000000..6f467df0
--- /dev/null
+++ b/packages/docs/app/components/demo/overlays/demo-modal.hbs
@@ -0,0 +1,37 @@
+
+ Open Modal
+
+
+
+
+ Title
+
+ Some contents...
+ Some contents...
+ Some contents...
+
+
+
+ Cancel
+
+
+ {{if this.isLoading "Loading..." "Save"}}
+
+
+
+
diff --git a/packages/docs/app/components/demo/overlays/demo-modal.ts b/packages/docs/app/components/demo/overlays/demo-modal.ts
new file mode 100644
index 00000000..c52003ab
--- /dev/null
+++ b/packages/docs/app/components/demo/overlays/demo-modal.ts
@@ -0,0 +1,28 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { action } from '@ember/object';
+import { later } from '@ember/runloop';
+
+interface DemoModalArgs {}
+
+export default class DemoModal extends Component {
+ @tracked isOpen = false;
+ @tracked isLoading = false;
+
+ @action toggleModal(): void {
+ this.isOpen = !this.isOpen;
+ }
+
+ @action save(): void {
+ this.isLoading = true;
+
+ later(
+ this,
+ () => {
+ this.isLoading = false;
+ this.isOpen = false;
+ },
+ 1000
+ );
+ }
+}
diff --git a/packages/docs/app/router.js b/packages/docs/app/router.js
index c7eb82bc..1f0c4ff5 100644
--- a/packages/docs/app/router.js
+++ b/packages/docs/app/router.js
@@ -35,6 +35,9 @@ Router.map(function () {
this.route('notifications', function () {
this.route('usage');
});
+ this.route('overlays', function () {
+ this.route('usage');
+ });
});
this.route('not-found', { path: '/*path' });
diff --git a/packages/docs/app/styles/tailwind.config.js b/packages/docs/app/styles/tailwind.config.js
index d982919c..98f0cdf6 100644
--- a/packages/docs/app/styles/tailwind.config.js
+++ b/packages/docs/app/styles/tailwind.config.js
@@ -7,6 +7,7 @@ module.exports = {
plugins: [
require('@frontile/forms/tailwind'),
require('@frontile/notifications/tailwind'),
+ require('@frontile/overlays/tailwind'),
require('@frontile/buttons/tailwind')
]
};
diff --git a/packages/docs/app/templates/docs.hbs b/packages/docs/app/templates/docs.hbs
index 5ee8ac34..759ab9a8 100644
--- a/packages/docs/app/templates/docs.hbs
+++ b/packages/docs/app/templates/docs.hbs
@@ -38,6 +38,10 @@
{{nav.item "Installation" "docs.notifications.index"}}
{{nav.item "Usage" "docs.notifications.usage"}}
+ {{nav.section "Overlays"}}
+ {{nav.item "Installation" "docs.overlays.index"}}
+ {{nav.item "Usage" "docs.overlays.usage"}}
+
{{nav.section "Buttons"}}
{{nav.item "Installation" "docs.buttons.index"}}
diff --git a/packages/docs/app/templates/docs/overlays/index.md b/packages/docs/app/templates/docs/overlays/index.md
new file mode 100644
index 00000000..3aaabb69
--- /dev/null
+++ b/packages/docs/app/templates/docs/overlays/index.md
@@ -0,0 +1,5 @@
+# Overlays Installation
+
+```sh
+ember install @frontile/overlays
+```
diff --git a/packages/docs/app/templates/docs/overlays/usage.md b/packages/docs/app/templates/docs/overlays/usage.md
new file mode 100644
index 00000000..0f9f3fc8
--- /dev/null
+++ b/packages/docs/app/templates/docs/overlays/usage.md
@@ -0,0 +1,3 @@
+# Modal
+
+
diff --git a/packages/docs/package.json b/packages/docs/package.json
index 8bcee7dc..adc17ec2 100644
--- a/packages/docs/package.json
+++ b/packages/docs/package.json
@@ -26,12 +26,13 @@
"@frontile/core": "^0.1.0-alpha.6",
"@frontile/forms": "^0.1.0-alpha.6",
"@frontile/notifications": "^0.1.0-alpha.6",
+ "@frontile/overlays": "^0.1.0-alpha.6",
"@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0",
"@types/ember": "^3.1.2",
"@types/ember-qunit": "^3.4.8",
"@types/ember__test-helpers": "^0.7.10",
- "@types/qunit": "^2.9.0",
+ "@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
"autoprefixer": "^9.7.5",
"broccoli-asset-rev": "^3.0.0",
@@ -58,7 +59,7 @@
"ember-maybe-import-regenerator": "^0.1.6",
"ember-qunit": "^4.6.0",
"ember-resolver": "^7.0.0",
- "ember-source": "^3.17.2",
+ "ember-source": "^3.17.3",
"loader.js": "^4.7.0",
"qunit-dom": "^1.1.0",
"tailwindcss": "^1.2.0",
diff --git a/packages/forms/package.json b/packages/forms/package.json
index 25e89d7f..be1d0be7 100644
--- a/packages/forms/package.json
+++ b/packages/forms/package.json
@@ -38,7 +38,7 @@
"@types/ember": "^3.1.2",
"@types/ember-qunit": "^3.4.8",
"@types/ember__test-helpers": "^0.7.10",
- "@types/qunit": "^2.9.0",
+ "@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
"autoprefixer": "^9.7.5",
"broccoli-asset-rev": "^3.0.0",
@@ -54,7 +54,7 @@
"ember-maybe-import-regenerator": "^0.1.6",
"ember-qunit": "^4.6.0",
"ember-resolver": "^7.0.0",
- "ember-source": "^3.17.2",
+ "ember-source": "^3.17.3",
"ember-try": "^1.4.0",
"loader.js": "^4.7.0",
"qunit-dom": "^1.1.0",
diff --git a/packages/notifications/package.json b/packages/notifications/package.json
index 8d4617a9..bfc7adf7 100644
--- a/packages/notifications/package.json
+++ b/packages/notifications/package.json
@@ -39,9 +39,9 @@
"@types/ember": "^3.1.2",
"@types/ember-qunit": "^3.4.8",
"@types/ember__test-helpers": "^0.7.10",
- "@types/qunit": "^2.9.0",
+ "@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
- "@types/sinon": "^7.5.2",
+ "@types/sinon": "^9.0.0",
"autoprefixer": "^9.7.5",
"broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.5.3",
@@ -58,7 +58,7 @@
"ember-qunit": "^4.6.0",
"ember-resolver": "^7.0.0",
"ember-sinon": "^5.0.0",
- "ember-source": "~3.17.2",
+ "ember-source": "~3.17.3",
"ember-try": "^1.4.0",
"loader.js": "^4.7.0",
"qunit-dom": "^1.1.0",
diff --git a/packages/overlays/addon/-private/dom.d.ts b/packages/overlays/addon/-private/dom.d.ts
new file mode 100644
index 00000000..fa026db0
--- /dev/null
+++ b/packages/overlays/addon/-private/dom.d.ts
@@ -0,0 +1,5 @@
+export function getDOM(context: unknown): null | HTMLDocument;
+export function getElementById(
+ doc: HTMLElement | HTMLDocument,
+ id: string
+): null | HTMLElement;
diff --git a/packages/overlays/addon/-private/dom.js b/packages/overlays/addon/-private/dom.js
new file mode 100644
index 00000000..e99dba0a
--- /dev/null
+++ b/packages/overlays/addon/-private/dom.js
@@ -0,0 +1,61 @@
+import { getOwner } from '@ember/application';
+
+// adjusted from https://github.com/yapplabs/ember-wormhole/blob/0.5.4/addon/utils/dom.js#L45-L63
+// Copied from https://github.com/ember-intl/ember-intl/blob/a66560d0af9f08af20778a3eb3003045e19fbf16/addon/-private/utils/get-dom.js
+//
+// Private Ember API usage. Get the dom implementation used by the current
+// renderer, be it native browser DOM or Fastboot SimpleDOM
+/**
+ * @private
+ * @hide
+ */
+export function getDOM(context) {
+ let { renderer } = context;
+ if (!renderer || !renderer._dom) {
+ // pre glimmer2
+ const container = getOwner ? getOwner(context) : context.container;
+ const documentService = container.lookup('service:-document');
+
+ if (documentService) {
+ return documentService;
+ }
+
+ renderer = container.lookup('renderer:-dom');
+ }
+
+ if (renderer._dom && renderer._dom.document) {
+ // pre Ember 2.6
+ return renderer._dom.document;
+ }
+
+ return null;
+}
+
+function childNodesOfElement(element) {
+ const children = [];
+ let child = element.firstChild;
+ while (child) {
+ children.push(child);
+ child = child.nextSibling;
+ }
+ return children;
+}
+
+export function getElementById(doc, id) {
+ if (doc.getElementById) {
+ return doc.getElementById(id);
+ }
+
+ let nodes = childNodesOfElement(doc);
+ let node;
+
+ while (nodes.length) {
+ node = nodes.shift();
+
+ if (node.getAttribute && node.getAttribute('id') === id) {
+ return node;
+ }
+
+ nodes = childNodesOfElement(node).concat(nodes);
+ }
+}
diff --git a/packages/overlays/addon/components/modal/body.hbs b/packages/overlays/addon/components/modal/body.hbs
new file mode 100644
index 00000000..ff2a6091
--- /dev/null
+++ b/packages/overlays/addon/components/modal/body.hbs
@@ -0,0 +1,6 @@
+
+ {{yield}}
+
diff --git a/packages/overlays/addon/components/modal/body.ts b/packages/overlays/addon/components/modal/body.ts
new file mode 100644
index 00000000..9f18050e
--- /dev/null
+++ b/packages/overlays/addon/components/modal/body.ts
@@ -0,0 +1,5 @@
+import Component from '@glimmer/component';
+
+interface ModalBodyArgs {}
+
+export default class ModalBody extends Component {}
diff --git a/packages/overlays/addon/components/modal/footer.hbs b/packages/overlays/addon/components/modal/footer.hbs
new file mode 100644
index 00000000..3bc584cb
--- /dev/null
+++ b/packages/overlays/addon/components/modal/footer.hbs
@@ -0,0 +1,6 @@
+
diff --git a/packages/overlays/addon/components/modal/footer.ts b/packages/overlays/addon/components/modal/footer.ts
new file mode 100644
index 00000000..a55bfe96
--- /dev/null
+++ b/packages/overlays/addon/components/modal/footer.ts
@@ -0,0 +1,5 @@
+import Component from '@glimmer/component';
+
+interface ModalFooterArgs {}
+
+export default class ModalFooter extends Component {}
diff --git a/packages/overlays/addon/components/modal/header.hbs b/packages/overlays/addon/components/modal/header.hbs
new file mode 100644
index 00000000..c57e5bab
--- /dev/null
+++ b/packages/overlays/addon/components/modal/header.hbs
@@ -0,0 +1,7 @@
+
diff --git a/packages/overlays/addon/components/modal/header.ts b/packages/overlays/addon/components/modal/header.ts
new file mode 100644
index 00000000..64abfa87
--- /dev/null
+++ b/packages/overlays/addon/components/modal/header.ts
@@ -0,0 +1,10 @@
+import Component from '@glimmer/component';
+
+interface ModalHeaderArgs {
+ /*
+ * The id used to reference labelledById in Modal component
+ */
+ labelledById: string;
+}
+
+export default class ModalHeader extends Component {}
diff --git a/packages/overlays/addon/components/modal/index.hbs b/packages/overlays/addon/components/modal/index.hbs
new file mode 100644
index 00000000..0d18aa04
--- /dev/null
+++ b/packages/overlays/addon/components/modal/index.hbs
@@ -0,0 +1,39 @@
+
+
+ {{#unless this.preventClosing}}
+
+
+ Close
+
+ {{/unless}}
+
+ {{yield (hash
+ Header=(component "modal/header" labelledById=this.headerId)
+ Body=(component "modal/body")
+ Footer=(component "modal/footer")
+ )}}
+
+
diff --git a/packages/overlays/addon/components/modal/index.ts b/packages/overlays/addon/components/modal/index.ts
new file mode 100644
index 00000000..e3e6792d
--- /dev/null
+++ b/packages/overlays/addon/components/modal/index.ts
@@ -0,0 +1,34 @@
+import Component from '@glimmer/component';
+import { action } from '@ember/object';
+import { guidFor } from '@ember/object/internals';
+import { OverlayArgs } from '../overlay';
+
+interface ModalArgs extends Omit {
+ /*
+ * The name of the transition to be used in the modal.
+ * @defaultValue `overlay--transition--zoom`
+ */
+ transitionName?: string;
+
+ /* If set to false, the close button will not be displayed,
+ * closeOnOutsideClick will be set to false, and closeOnEscapeKey will also be set
+ * to false.
+ *
+ * @defaultValue true
+ */
+ allowClosing?: boolean;
+}
+
+export default class Modal extends Component {
+ headerId = `${guidFor(this)}-header`;
+
+ get preventClosing(): boolean {
+ return this.args.allowClosing === false;
+ }
+
+ @action handleClose(): void {
+ if (typeof this.args.onClose === 'function') {
+ this.args.onClose();
+ }
+ }
+}
diff --git a/packages/overlays/addon/components/overlay.hbs b/packages/overlays/addon/components/overlay.hbs
new file mode 100644
index 00000000..e21edae1
--- /dev/null
+++ b/packages/overlays/addon/components/overlay.hbs
@@ -0,0 +1,68 @@
+{{!--
+ Here are the css classes we use. This is here so that purgecss doesn't remove them.
+ js-overlay-is-open
+ overlay--transition--fade-enter
+ overlay--transition--fade-enter-active
+ overlay--transition--fade-leave
+ overlay--transition--fade-leave-active
+ overlay--transition--zoom-enter
+ overlay--transition--zoom-enter-active
+ overlay--transition--zoom-leave
+ overlay--transition--zoom-leave-active
+--}}
+
+{{#if this.isVisible}}
+ {{#maybe-in-element this.destinationElement @renderInPlace insertBefore=null}}
+
+ {{!-- template-lint-disable no-invalid-interactive --}}
+ {{#if this.isBackdropVisible}}
+ {{#if @disableTransitions}}
+
+ {{else}}
+
+ {{/if}}
+ {{/if}}
+
+ {{!--
+ This is required to make css-transition work with 2
+ sibling elements been removed at the same time.
+ --}}
+
+
+ {{#if @isOpen}}
+ {{#if @disableTransitions}}
+
+ {{yield}}
+
+ {{else}}
+
+ {{yield}}
+
+ {{/if}}
+ {{/if}}
+ {{!-- template-lint-enable no-invalid-interactive --}}
+
+ {{/maybe-in-element}}
+{{/if}}
diff --git a/packages/overlays/addon/components/overlay.ts b/packages/overlays/addon/components/overlay.ts
new file mode 100644
index 00000000..bb723376
--- /dev/null
+++ b/packages/overlays/addon/components/overlay.ts
@@ -0,0 +1,164 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { action } from '@ember/object';
+import { later } from '@ember/runloop';
+import { getDOM, getElementById } from '../-private/dom';
+
+export interface OverlayArgs {
+ /*
+ * Whether to render in place or in the specified/default destination
+ * @defaultValue false
+ */
+ renderInPlace?: boolean;
+
+ /*
+ * The destination where the overlay will be inserted, defaults to
+ * `document.body`
+ * @defaultValue undefined
+ */
+ destinationElementId?: string;
+
+ /*
+ * Duration of the animation
+ * @defaultValue 200
+ */
+ transitionDuration?: number;
+
+ /*
+ * Whether to hide the backdrop or not
+ * @defaultValue false
+ */
+ disableBackdrop?: boolean;
+
+ /*
+ * Disable css transitions
+ * @defaultValue false
+ */
+ disableTransitions?: boolean;
+
+ /*
+ * Whether the focus trap is disabled or not
+ * @defaultValue false
+ */
+ disableFocusTrap?: boolean;
+
+ /*
+ * Whether it is open or not
+ * @defaultValue false
+ */
+ isOpen?: boolean;
+
+ /*
+ * A function that will be called when closed
+ * @defaultValue true
+ */
+ onClose?: () => void;
+
+ /*
+ * Whether to close when the area outside (the backdrop) is clicked
+ * @defaultValue true
+ */
+ closeOnOutsideClick?: boolean;
+
+ /*
+ * Whether to close when the escape key is pressed
+ * @defaultValue true
+ */
+ closeOnEscapeKey?: boolean;
+
+ /*
+ * The name of the transition to be used in the backdrop.
+ * @defaultValue `overlay--transition--fade`
+ */
+ backdropTransitionName?: string;
+
+ /*
+ * The name of the transition to be used in the content.
+ * @defaultValue `overlay--transition--fade`
+ */
+ contentTransitionName?: string;
+}
+
+export default class Overlay extends Component {
+ @tracked keepOpen = false;
+ contentElement: HTMLElement | undefined;
+
+ get destinationElement(): HTMLElement | null {
+ const doc = getDOM(this);
+
+ if (!doc) {
+ return null;
+ }
+
+ if (this.args.destinationElementId) {
+ return getElementById(doc, this.args.destinationElementId);
+ } else {
+ return doc.body;
+ }
+ }
+
+ get isVisible(): boolean {
+ return this.args.isOpen || this.keepOpen;
+ }
+
+ get isBackdropVisible(): boolean {
+ return this.args.isOpen === true && this.args.disableBackdrop !== true;
+ }
+
+ @action handleOverlayClick(): void {
+ if (this.args.closeOnOutsideClick !== false) {
+ this.handleClose();
+ }
+ }
+
+ @action handleContentClick(event: MouseEvent): void {
+ if (
+ this.args.closeOnOutsideClick !== false &&
+ event.target === this.contentElement
+ ) {
+ this.handleClose();
+ }
+ }
+
+ @action handleClose(): void {
+ if (typeof this.args.onClose === 'function') {
+ this.args.onClose();
+ }
+ }
+
+ @action
+ handleKeyDown(event: KeyboardEvent): void {
+ if (event.key === 'Escape' && this.args.closeOnEscapeKey !== false) {
+ this.handleClose();
+ }
+ }
+
+ @action setup(element: HTMLElement): void {
+ this.contentElement = element;
+ this.keepOpen = true;
+ document.addEventListener('keydown', this.handleKeyDown);
+
+ if (this.args.renderInPlace !== true) {
+ document.body.classList.add('js-overlay-is-open');
+ }
+ }
+
+ @action teardown(): void {
+ this.contentElement = undefined;
+ document.removeEventListener('keydown', this.handleKeyDown);
+
+ if (this.args.renderInPlace !== true && document.body.classList) {
+ document.body.classList.remove('js-overlay-is-open');
+ }
+
+ let duration = this.args.transitionDuration || 200;
+
+ if (this.args.disableTransitions === true) {
+ duration = 0;
+ }
+
+ later(() => {
+ if (!this.isDestroyed) this.keepOpen = false;
+ }, duration);
+ }
+}
diff --git a/packages/overlays/addon/tailwind/default-options.js b/packages/overlays/addon/tailwind/default-options.js
index e55b635c..de0deb7d 100644
--- a/packages/overlays/addon/tailwind/default-options.js
+++ b/packages/overlays/addon/tailwind/default-options.js
@@ -1,6 +1,6 @@
-// const defaultTheme = require('tailwindcss/resolveConfig')(
-// require('tailwindcss/defaultConfig')
-// ).theme;
+const defaultTheme = require('tailwindcss/resolveConfig')(
+ require('tailwindcss/defaultConfig')
+).theme;
const defaultConfig = {
// empty for now
@@ -8,7 +8,159 @@ const defaultConfig = {
function defaultOptions(/*{ config }*/) {
return {
- default: {}
+ default: {
+ transitions: {
+ fade: {
+ enter: {
+ opacity: 0
+ },
+ enterActive: {
+ opacity: 1,
+ transition: 'opacity 0.2s linear'
+ },
+ leave: {
+ opacity: 1
+ },
+ leaveActive: {
+ opacity: 0,
+ transition: 'opacity 0.2s linear'
+ }
+ },
+ zoom: {
+ enter: {
+ opacity: 0,
+ transform: 'scale(0.8)'
+ },
+ enterActive: {
+ opacity: 1,
+ transform: 'scale(1)',
+ transition: 'all 0.2s ease-in-out'
+ },
+ leave: {
+ opacity: 1,
+ transform: 'scale(1)'
+ },
+ leaveActive: {
+ opacity: 0,
+ transform: 'scale(0.8)',
+ transition: 'all 0.2s ease-in-out'
+ }
+ }
+ },
+
+ overlay: {
+ zIndex: 50,
+ overflow: 'auto',
+ position: 'fixed',
+ top: 0,
+ bottom: 0,
+ right: 0,
+ left: 0,
+ '-webkit-overflow-scrolling': 'touch',
+
+ jsIsOpen: {
+ overflow: 'hidden'
+ },
+
+ backdrop: {
+ position: 'fixed',
+ top: 0,
+ bottom: 0,
+ right: 0,
+ left: 0,
+ overflow: 'auto',
+ backgroundColor: 'rgba(0, 0, 0, 0.45)',
+ userSelect: 'none'
+ },
+
+ content: {
+ position: 'relative'
+ }
+ },
+ modal: {
+ position: 'relative',
+ backgroundColor: defaultTheme.colors.white,
+ borderRadius: defaultTheme.borderRadius.default,
+ boxShadow: defaultTheme.boxShadow.default,
+ maxWidth: defaultTheme.maxWidth['xl'],
+ marginLeft: 'auto',
+ marginRight: 'auto',
+ outline: 'none',
+ top: defaultTheme.spacing[24],
+ marginBottom: defaultTheme.margin[4],
+
+ [`@media (max-width: ${defaultTheme.screens.sm})`]: {
+ maxWidth: `calc(100vw - ${defaultTheme.margin[4]})`
+ },
+
+ closeBtn: {
+ display: 'flex',
+ position: 'absolute',
+ fontSize: defaultTheme.fontSize.xl,
+ padding: defaultTheme.spacing[2],
+ top: defaultTheme.padding[2],
+ right: defaultTheme.padding[2],
+ transitionProperty: defaultTheme.transitionProperty.default,
+ transitionDuration: defaultTheme.transitionDuration[200],
+ borderRadius: defaultTheme.borderRadius.full,
+
+ '&:hover': {
+ backgroundColor: defaultTheme.colors.gray[200]
+ },
+
+ '&.focus-visible:focus': {
+ outline: 'none',
+ boxShadow: defaultTheme.boxShadow.outline
+ },
+
+ icon: {
+ display: 'inline-block',
+ height: '1em',
+ width: '1em',
+ backgroundRepeat: 'no-repeat',
+ iconColor: 'currentColor',
+ icon: (iconColor) =>
+ ` `
+ }
+ },
+
+ header: {
+ fontWeight: defaultTheme.fontWeight.bold,
+ fontSize: defaultTheme.fontSize.xl,
+ paddingTop: defaultTheme.padding[4],
+ paddingBottom: defaultTheme.padding[4],
+ paddingRight: defaultTheme.padding[4],
+ paddingLeft: defaultTheme.padding[4]
+ },
+ body: {
+ paddingTop: defaultTheme.padding[4],
+ paddingBottom: defaultTheme.padding[8],
+ paddingRight: defaultTheme.padding[4],
+ paddingLeft: defaultTheme.padding[4]
+ },
+ footer: {
+ display: 'flex',
+ justifyContent: 'flex-end',
+ backgroundColor: defaultTheme.colors.gray[100],
+ borderTopWidth: defaultTheme.borderWidth.default,
+ borderTopColor: defaultTheme.borderColor.default,
+ paddingTop: defaultTheme.padding[4],
+ paddingBottom: defaultTheme.padding[4],
+ paddingRight: defaultTheme.padding[4],
+ paddingLeft: defaultTheme.padding[4],
+ borderBottomRightRadius: defaultTheme.borderRadius.default,
+ borderBottomLeftRadius: defaultTheme.borderRadius.default
+ }
+ }
+ },
+ 'in-place': {
+ overlay: {
+ position: 'absolute',
+ backdrop: {
+ position: 'absolute'
+ }
+ }
+ }
};
}
diff --git a/packages/overlays/app/components/modal.js b/packages/overlays/app/components/modal.js
new file mode 100644
index 00000000..97caa8f1
--- /dev/null
+++ b/packages/overlays/app/components/modal.js
@@ -0,0 +1 @@
+export { default } from '@frontile/overlays/components/modal';
diff --git a/packages/overlays/app/components/modal/body.js b/packages/overlays/app/components/modal/body.js
new file mode 100644
index 00000000..89a010a2
--- /dev/null
+++ b/packages/overlays/app/components/modal/body.js
@@ -0,0 +1 @@
+export { default } from '@frontile/overlays/components/modal/body';
diff --git a/packages/overlays/app/components/modal/footer.js b/packages/overlays/app/components/modal/footer.js
new file mode 100644
index 00000000..e3d2ebb0
--- /dev/null
+++ b/packages/overlays/app/components/modal/footer.js
@@ -0,0 +1 @@
+export { default } from '@frontile/overlays/components/modal/footer';
diff --git a/packages/overlays/app/components/modal/header.js b/packages/overlays/app/components/modal/header.js
new file mode 100644
index 00000000..5b095a9f
--- /dev/null
+++ b/packages/overlays/app/components/modal/header.js
@@ -0,0 +1 @@
+export { default } from '@frontile/overlays/components/modal/header';
diff --git a/packages/overlays/app/components/overlay.js b/packages/overlays/app/components/overlay.js
new file mode 100644
index 00000000..4f812ca4
--- /dev/null
+++ b/packages/overlays/app/components/overlay.js
@@ -0,0 +1 @@
+export { default } from '@frontile/overlays/components/overlay';
diff --git a/packages/overlays/ember-cli-build.js b/packages/overlays/ember-cli-build.js
index 2465495e..89e8a983 100644
--- a/packages/overlays/ember-cli-build.js
+++ b/packages/overlays/ember-cli-build.js
@@ -3,11 +3,15 @@
const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
const path = require('path');
+// Enable FastBoot Rehydration
+// process.env.EXPERIMENTAL_RENDER_MODE_SERIALIZE = true;
+
module.exports = function (defaults) {
const app = new EmberAddon(defaults, {
postcssOptions: {
compile: {
enabled: true,
+ cacheInclude: [/.*\.css$/, /.tailwind\.config\.js$/],
plugins: [
require('tailwindcss')(
path.join('tests', 'dummy', 'app', 'styles', 'tailwind.config.js')
diff --git a/packages/overlays/package.json b/packages/overlays/package.json
index efd7d408..6f37416a 100644
--- a/packages/overlays/package.json
+++ b/packages/overlays/package.json
@@ -1,6 +1,6 @@
{
"name": "@frontile/overlays",
- "version": "0.0.0",
+ "version": "0.1.0-alpha.6",
"description": "Component Library for Ember Octane apps: overlays",
"keywords": [
"ember-addon"
@@ -22,26 +22,33 @@
"try:one": "ember try:one"
},
"dependencies": {
+ "@ember/render-modifiers": "^1.0.2",
+ "@frontile/core": "^0.1.0-alpha.6",
"@frontile/tailwindcss-plugin-helpers": "^0.1.0-alpha.5",
"ember-cli-babel": "^7.17.2",
"ember-cli-htmlbars": "^4.2.2",
- "ember-cli-typescript": "^3.1.3"
+ "ember-cli-typescript": "^3.1.3",
+ "ember-css-transitions": "^1.0.1",
+ "ember-focus-trap": "^0.4.0",
+ "ember-maybe-in-element": "^0.4.0"
},
"devDependencies": {
"@babel/core": "^7.8.6",
"@ember/optional-features": "^1.3.0",
+ "@frontile/buttons": "^0.1.0-alpha.6",
"@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0",
"@types/ember": "^3.1.1",
"@types/ember-qunit": "^3.4.7",
"@types/ember__test-helpers": "^0.7.9",
- "@types/qunit": "^2.9.0",
+ "@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
"autoprefixer": "^9.7.4",
"broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.5.3",
"ember-cli": "~3.17.0",
"ember-cli-dependency-checker": "^3.2.0",
+ "ember-cli-fastboot": "^2.2.1",
"ember-cli-inject-live-reload": "^2.0.2",
"ember-cli-postcss": "^6.0.0",
"ember-cli-sri": "^2.1.1",
@@ -52,7 +59,7 @@
"ember-maybe-import-regenerator": "^0.1.6",
"ember-qunit": "^4.6.0",
"ember-resolver": "^7.0.0",
- "ember-source": "~3.17.2",
+ "ember-source": "~3.17.3",
"ember-try": "^1.4.0",
"loader.js": "^4.7.0",
"qunit-dom": "^1.0.0",
diff --git a/packages/overlays/tailwind.js b/packages/overlays/tailwind.js
index 149b4823..20714f11 100644
--- a/packages/overlays/tailwind.js
+++ b/packages/overlays/tailwind.js
@@ -1,5 +1,10 @@
const plugin = require('tailwindcss/plugin');
-const { resolve, isEmpty } = require('@frontile/tailwindcss-plugin-helpers');
+const {
+ resolve,
+ isEmpty,
+ svgToDataUri,
+ replaceIconDeclarations
+} = require('@frontile/tailwindcss-plugin-helpers');
module.exports = plugin.withOptions(function (userConfig) {
return function ({ addComponents, theme }) {
@@ -10,16 +15,94 @@ module.exports = plugin.withOptions(function (userConfig) {
theme
);
- function addTODO(options, modifier) {
+ function addTransitionPhases(name, options) {
if (isEmpty(options)) {
return;
}
- addComponents({ [`.TODO${modifier}`]: options });
+ const { enter, enterActive, leave, leaveActive } = options || {};
+
+ name = `.overlay--transition--${name}`;
+
+ addComponents({ [`${name}-enter`]: enter });
+ addComponents({ [`${name}-enter-active`]: enterActive });
+ addComponents({ [`${name}-leave`]: leave });
+ addComponents({ [`${name}-leave-active`]: leaveActive });
+ }
+
+ function addTransitions(options) {
+ if (isEmpty(options)) {
+ return;
+ }
+
+ Object.keys(options).forEach((key) => {
+ addTransitionPhases(key, options[key]);
+ });
+ }
+
+ function addOverlay(options, modifier) {
+ if (isEmpty(options)) {
+ return;
+ }
+ addComponents({ [`.overlay${modifier}`]: options });
+ addComponents({
+ [`.overlay${modifier} .overlay__backdrop`]: options.backdrop
+ });
+
+ addComponents({
+ [`.overlay${modifier} .overlay__content`]: options.content
+ });
+
+ addComponents({ [`.js-overlay-is-open`]: options.jsIsOpen });
}
+ function addModal(options, modifier) {
+ if (isEmpty(options)) {
+ return;
+ }
+ const { closeBtn } = options;
+ delete options.closeBtn;
+
+ addComponents({ [`.modal${modifier}`]: options });
+ addComponents({
+ [`.modal${modifier} .modal__header`]: options.header
+ });
+
+ const { icon: btnIcon } = closeBtn;
+ delete closeBtn.icon;
+
+ addComponents({
+ [`.modal${modifier} .modal__close-btn`]: closeBtn
+ });
+
+ addComponents(
+ replaceIconDeclarations(
+ {
+ [`.modal${modifier} .modal__close-btn--icon`]: btnIcon
+ },
+ ({ icon = btnIcon.icon, iconColor = btnIcon.iconColor }) => {
+ return {
+ backgroundImage: `url("${svgToDataUri(
+ typeof icon === 'function' ? icon(iconColor) : icon
+ )}")`
+ };
+ }
+ )
+ );
+
+ addComponents({
+ [`.modal${modifier} .modal__body`]: options.body
+ });
+ addComponents({
+ [`.modal${modifier} .modal__footer`]: options.footer
+ });
+ }
+
+ addTransitions(options.default.transitions);
+
Object.keys(options).forEach((key) => {
- const modifier = key === 'default' ? '' : `-${key}`;
- addTODO(options[key].TODO, modifier);
+ const modifier = key === 'default' ? '' : `--${key}`;
+ addOverlay(options[key].overlay, modifier);
+ addModal(options[key].modal, modifier);
});
};
});
diff --git a/packages/overlays/tests/dummy/app/components/demo-modal.hbs b/packages/overlays/tests/dummy/app/components/demo-modal.hbs
new file mode 100644
index 00000000..6f467df0
--- /dev/null
+++ b/packages/overlays/tests/dummy/app/components/demo-modal.hbs
@@ -0,0 +1,37 @@
+
+ Open Modal
+
+
+
+
+ Title
+
+ Some contents...
+ Some contents...
+ Some contents...
+
+
+
+ Cancel
+
+
+ {{if this.isLoading "Loading..." "Save"}}
+
+
+
+
diff --git a/packages/overlays/tests/dummy/app/components/demo-modal.ts b/packages/overlays/tests/dummy/app/components/demo-modal.ts
new file mode 100644
index 00000000..c52003ab
--- /dev/null
+++ b/packages/overlays/tests/dummy/app/components/demo-modal.ts
@@ -0,0 +1,28 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { action } from '@ember/object';
+import { later } from '@ember/runloop';
+
+interface DemoModalArgs {}
+
+export default class DemoModal extends Component {
+ @tracked isOpen = false;
+ @tracked isLoading = false;
+
+ @action toggleModal(): void {
+ this.isOpen = !this.isOpen;
+ }
+
+ @action save(): void {
+ this.isLoading = true;
+
+ later(
+ this,
+ () => {
+ this.isLoading = false;
+ this.isOpen = false;
+ },
+ 1000
+ );
+ }
+}
diff --git a/packages/overlays/tests/dummy/app/styles/tailwind.config.js b/packages/overlays/tests/dummy/app/styles/tailwind.config.js
index e639a83e..36be94e0 100644
--- a/packages/overlays/tests/dummy/app/styles/tailwind.config.js
+++ b/packages/overlays/tests/dummy/app/styles/tailwind.config.js
@@ -14,5 +14,8 @@ module.exports = {
extend: {}
},
variants: {},
- plugins: [require('@frontile/overlays/tailwind')]
+ plugins: [
+ require('@frontile/overlays/tailwind'),
+ require('@frontile/buttons/tailwind')
+ ]
};
diff --git a/packages/overlays/tests/dummy/app/templates/index.hbs b/packages/overlays/tests/dummy/app/templates/index.hbs
new file mode 100644
index 00000000..9c3112a7
--- /dev/null
+++ b/packages/overlays/tests/dummy/app/templates/index.hbs
@@ -0,0 +1 @@
+
diff --git a/packages/overlays/tests/integration/components/modal-test.ts b/packages/overlays/tests/integration/components/modal-test.ts
new file mode 100644
index 00000000..9297a8bf
--- /dev/null
+++ b/packages/overlays/tests/integration/components/modal-test.ts
@@ -0,0 +1,169 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find, click, triggerKeyEvent } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | modal', function (hooks) {
+ setupRenderingTest(hooks);
+
+ const template = hbs`
+
+
+ My Header
+ My Content
+ My Footer
+
+ `;
+
+ test('it renders, header, body, footer, and close-btn', async function (assert) {
+ this.set('isOpen', true);
+ await render(template);
+
+ assert.dom('[data-test-id="modal"]').exists();
+ assert.dom('[data-test-id="modal"] .modal__header').hasText('My Header');
+ assert.dom('[data-test-id="modal"] .modal__body').hasText('My Content');
+ assert.dom('[data-test-id="modal"] .modal__footer').hasText('My Footer');
+ assert.dom('[data-test-id="modal"] .modal__close-btn').hasText('Close');
+ });
+
+ test('it renders accessibility attributes', async function (assert) {
+ this.set('isOpen', true);
+ await render(template);
+
+ assert.dom('[data-test-id="modal"]').hasAttribute('tabindex', '0');
+ assert.dom('[data-test-id="modal"]').hasAttribute('role', 'dialog');
+ assert.dom('[data-test-id="modal"]').hasAttribute('aria-labelledby');
+
+ const ariaLablledBy =
+ find('[data-test-id="modal"]')?.getAttribute('aria-labelledby') || '';
+ assert
+ .dom('[data-test-id="modal"] .modal__header')
+ .hasAttribute('id', ariaLablledBy);
+ });
+
+ test('it closes modal when close button is clicked', async function (assert) {
+ assert.expect(3);
+
+ this.set('disableTransitions', true);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(true);
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+
+ assert.dom('[data-test-id="modal"]').exists();
+ await click('[data-test-id="modal"] .modal__close-btn');
+ assert.dom('[data-test-id="modal"]').doesNotExist();
+ });
+
+ test('it closes modal when backdrop is clicked', async function (assert) {
+ assert.expect(3);
+
+ this.set('disableTransitions', true);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(true);
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+
+ assert.dom('[data-test-id="modal"]').exists();
+ await click('.overlay__backdrop');
+ assert.dom('[data-test-id="modal"]').doesNotExist();
+ });
+
+ test('when @closeOnOutsideClick={{false}} does not close modal', async function (assert) {
+ assert.expect(1);
+
+ this.set('closeOnOutsideClick', false);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(false, 'should not have been called');
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+ await click('.overlay__backdrop');
+ assert.dom('[data-test-id="modal"]').exists();
+ });
+
+ test('it closes modal when pressing Escape', async function (assert) {
+ assert.expect(2);
+
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(true);
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+ await triggerKeyEvent(document as never, 'keydown', 'Escape');
+ assert.dom('[data-test-id="modal"]').doesNotExist();
+ });
+
+ test('when @closeOnEscapeKey={{false}} does not close modal', async function (assert) {
+ assert.expect(1);
+
+ this.set('closeOnEscapeKey', false);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(false, 'should not have been called');
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+ await triggerKeyEvent(document as never, 'keydown', 'Escape');
+ assert.dom('[data-test-id="modal"]').exists();
+ });
+
+ test('when @allowClosing={{false}} does not close modal', async function (assert) {
+ assert.expect(4);
+
+ this.set('allowClosing', false);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(false, 'should not have been called');
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+
+ assert.dom('[data-test-id="modal"]').exists();
+ assert.dom('[data-test-id="modal"] .modal__close-btn').doesNotExist();
+
+ await click('.overlay__backdrop');
+ assert.dom('[data-test-id="modal"]').exists();
+
+ await triggerKeyEvent(document as never, 'keydown', 'Escape');
+ assert.dom('[data-test-id="modal"]').exists();
+ });
+
+ test('when @renderInPlace={{true}} renders in place', async function (assert) {
+ this.set('renderInPlace', true);
+ this.set('isOpen', true);
+
+ await render(template);
+ assert.dom('.my-destination > [data-test-id="modal"]').doesNotExist();
+ assert.dom('[data-test-id="modal"]', this.element).exists();
+ });
+});
diff --git a/packages/overlays/tests/integration/components/modal/body-test.ts b/packages/overlays/tests/integration/components/modal/body-test.ts
new file mode 100644
index 00000000..814a2224
--- /dev/null
+++ b/packages/overlays/tests/integration/components/modal/body-test.ts
@@ -0,0 +1,20 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | Modal::Body', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders, content and html attributes', async function (assert) {
+ await render(hbs`
+
+ My Body
+
+ `);
+
+ assert.dom('[data-test-id="body"]').hasText('My Body');
+ assert.dom('[data-test-id="body"]').hasClass('modal__body');
+ assert.dom('[data-test-id="body"]').hasClass('other-class');
+ });
+});
diff --git a/packages/overlays/tests/integration/components/modal/footer-test.ts b/packages/overlays/tests/integration/components/modal/footer-test.ts
new file mode 100644
index 00000000..a9612edb
--- /dev/null
+++ b/packages/overlays/tests/integration/components/modal/footer-test.ts
@@ -0,0 +1,20 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | Modal::Footer', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders, content and html attributes', async function (assert) {
+ await render(hbs`
+
+ My Footer
+
+ `);
+
+ assert.dom('[data-test-id="footer"]').hasText('My Footer');
+ assert.dom('[data-test-id="footer"]').hasClass('modal__footer');
+ assert.dom('[data-test-id="footer"]').hasClass('other-class');
+ });
+});
diff --git a/packages/overlays/tests/integration/components/modal/header-test.ts b/packages/overlays/tests/integration/components/modal/header-test.ts
new file mode 100644
index 00000000..25780a29
--- /dev/null
+++ b/packages/overlays/tests/integration/components/modal/header-test.ts
@@ -0,0 +1,21 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | Modal::Header', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders, content, html attributes, and @labelledById', async function (assert) {
+ await render(hbs`
+
+ My Header
+
+ `);
+
+ assert.dom('[data-test-id="header"]').hasText('My Header');
+ assert.dom('[data-test-id="header"]').hasAttribute('id', 'hello');
+ assert.dom('[data-test-id="header"]').hasClass('modal__header');
+ assert.dom('[data-test-id="header"]').hasClass('other-class');
+ });
+});
diff --git a/packages/overlays/tests/integration/components/overlay-test.ts b/packages/overlays/tests/integration/components/overlay-test.ts
new file mode 100644
index 00000000..2fee304b
--- /dev/null
+++ b/packages/overlays/tests/integration/components/overlay-test.ts
@@ -0,0 +1,153 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, settled, click, triggerKeyEvent } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | Overlay', function (hooks) {
+ setupRenderingTest(hooks);
+
+ const template = hbs`
+
+
+ My Content
+ Something focusable
+
+ `;
+
+ test('it renders the content, into destination and only when opened', async function (assert) {
+ this.set('disableTransitions', true);
+ this.set('isOpen', true);
+ await render(template);
+ await settled();
+
+ assert.dom('[data-test-id="overlay"]').exists();
+ assert
+ .dom('[data-test-id="overlay"] .overlay__content')
+ .hasText('My Content Something focusable');
+
+ assert.dom('[data-test-id="overlay"] .overlay__backdrop').exists();
+
+ assert.dom('#my-destination > [data-test-id="overlay"]').exists();
+
+ this.set('isOpen', false);
+ await settled();
+ assert.dom('[data-test-id="overlay"]').doesNotExist();
+ });
+
+ test('when @renderInPlace={{true}} renders in place', async function (assert) {
+ this.set('disableTransitions', true);
+ this.set('renderInPlace', true);
+ this.set('isOpen', true);
+
+ await render(template);
+ assert.dom('.my-destination > [data-test-id="overlay"]').doesNotExist();
+ assert.dom('[data-test-id="overlay"]', this.element).exists();
+ assert.dom('[data-test-id="overlay"].overlay--in-place').exists();
+ });
+
+ test('when @disableBackdrop=true does not render backdrop', async function (assert) {
+ this.set('disableTransitions', true);
+ this.set('isOpen', true);
+ this.set('disableBackdrop', true);
+ await render(template);
+
+ assert.dom('[data-test-id="overlay"] .overlay__backdrop').doesNotExist();
+ });
+
+ test('it closes overlay when backdrop is clicked', async function (assert) {
+ assert.expect(2);
+
+ this.set('disableTransitions', true);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(true);
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+ await click('[data-test-id="overlay"] .overlay__backdrop');
+ assert.dom('[data-test-id="overlay"]').doesNotExist();
+ });
+
+ test('when @closeOnOutsideClick={{false}} does not close overlay', async function (assert) {
+ assert.expect(1);
+
+ this.set('disableTransitions', true);
+ this.set('closeOnOutsideClick', false);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(false, 'should not have been called');
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+ await click('[data-test-id="overlay"] .overlay__backdrop');
+ assert.dom('[data-test-id="overlay"]').exists();
+ });
+
+ test('it closes overlay when pressing Escape', async function (assert) {
+ assert.expect(2);
+
+ this.set('disableTransitions', true);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(true);
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+ await triggerKeyEvent(document as never, 'keydown', 'Escape');
+ assert.dom('[data-test-id="overlay"]').doesNotExist();
+ });
+
+ test('when @closeOnEscapeKey={{false}} does not close overlay', async function (assert) {
+ assert.expect(1);
+
+ this.set('disableTransitions', true);
+ this.set('closeOnEscapeKey', false);
+ this.set('isOpen', true);
+
+ this.set('onClose', () => {
+ assert.ok(false, 'should not have been called');
+ this.set('isOpen', false);
+ });
+
+ await render(template);
+ await triggerKeyEvent(document as never, 'keydown', 'Escape');
+ assert.dom('[data-test-id="overlay"]').exists();
+ });
+
+ test('it adds class to body to disable scroll', async function (assert) {
+ this.set('disableTransitions', true);
+ this.set('isOpen', true);
+
+ await render(template);
+ assert.dom(document.body).hasClass('js-overlay-is-open');
+ });
+
+ test('it does not add class to body when renderInPlace', async function (assert) {
+ this.set('isOpen', true);
+ this.set('renderInPlace', true);
+ this.set('disableTransitions', true);
+
+ await render(template);
+ assert.dom(document.body).doesNotHaveClass('js-overlay-is-open');
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 3aa7a0a9..637fc891 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2073,11 +2073,37 @@
dependencies:
"@types/node" ">= 8"
+"@simple-dom/document@^1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@simple-dom/document/-/document-1.4.0.tgz#af60855f957f284d436983798ef1006cca1a1678"
+ integrity sha512-/RUeVH4kuD3rzo5/91+h4Z1meLSLP66eXqpVAw/4aZmYozkeqUkMprq0znL4psX/adEed5cBgiNJcfMz/eKZLg==
+ dependencies:
+ "@simple-dom/interface" "^1.4.0"
+
"@simple-dom/interface@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@simple-dom/interface/-/interface-1.4.0.tgz#e8feea579232017f89b0138e2726facda6fbb71f"
integrity sha512-l5qumKFWU0S+4ZzMaLXFU8tQZsicHEMEyAxI5kDFGhJsRqDwe0a7/iPA/GdxlGyDKseQQAgIz5kzU7eXTrlSpA==
+"@simple-dom/parser@^1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@simple-dom/parser/-/parser-1.4.0.tgz#b1fee1a23f48a37d6bdd98f5242db0cab5b67abc"
+ integrity sha512-TNjDkOehueRIKr1df416qk9ELj+qWuVVJNIT25y1aZg3pQvxv4UPGrgaDFte7dsWBTbF3V8NYPNQ5FDUZQ8Wlg==
+ dependencies:
+ "@simple-dom/interface" "^1.4.0"
+
+"@simple-dom/serializer@^1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@simple-dom/serializer/-/serializer-1.4.0.tgz#98470f357f418d72b1a1ec78d68191e60aefe215"
+ integrity sha512-mI1yRahsVs8atXLiQksineDsFEFqeG7RHwnnBTDOK6inbzl4tZQgjR+Z7edjgIJq5j5RhZvwPI6EuCji9B3eQw==
+ dependencies:
+ "@simple-dom/interface" "^1.4.0"
+
+"@simple-dom/void-map@^1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@simple-dom/void-map/-/void-map-1.4.0.tgz#f15f07568fe1076740407266aa5e6eac249bc78c"
+ integrity sha512-VDhLEyVCbuhOBBgHol9ShzIv9O8UCzdXeH4FoXu2DOcu/nnvTjLTck+BgXsCLv5ynDiUdoqsREEVFnoyPpFKVw==
+
"@sindresorhus/is@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
@@ -2440,10 +2466,10 @@
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.1.tgz#937fab3194766256ee09fcd40b781740758617e7"
integrity sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw==
-"@types/qunit@^2.9.0":
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.9.0.tgz#0b3fcbe2b92f067856adac82ba3afbc66d8835ac"
- integrity sha512-Hx34HZmTJKRay+x3sFdEK62I8Z8YSWYg+rAlNr4M+AbwvNUJYxTTmWEH4a8B9ZN+Fl61awFrw+oRicWLFVugvQ==
+"@types/qunit@^2.9.1":
+ version "2.9.1"
+ resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.9.1.tgz#6083a42907ae6c9eecece794844bc3f8659e6c03"
+ integrity sha512-v51Fz/orMOkBGzrRvskky3UN0I81ka6rokAxkcuVyLHAh0qNKp+Roqympg/gTia8vGOIEbeSykevI0VKiIF13Q==
"@types/range-parser@*":
version "1.2.3"
@@ -2471,10 +2497,17 @@
"@types/express-serve-static-core" "*"
"@types/mime" "*"
-"@types/sinon@^7.5.2":
- version "7.5.2"
- resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.5.2.tgz#5e2f1d120f07b9cda07e5dedd4f3bf8888fccdb9"
- integrity sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==
+"@types/sinon@^9.0.0":
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.0.tgz#5b70a360f55645dd64f205defd2a31b749a59799"
+ integrity sha512-v2TkYHkts4VXshMkcmot/H+ERZ2SevKa10saGaJPGCJ8vh3lKrC4u663zYEeRZxep+VbG6YRDtQ6gVqw9dYzPA==
+ dependencies:
+ "@types/sinonjs__fake-timers" "*"
+
+"@types/sinonjs__fake-timers@*":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e"
+ integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==
"@types/sizzle@*":
version "2.3.2"
@@ -4261,7 +4294,7 @@ broccoli-clean-css@^1.1.0:
inline-source-map-comment "^1.0.5"
json-stable-stringify "^1.0.0"
-broccoli-concat@^3.2.2, broccoli-concat@^3.7.3, broccoli-concat@^3.7.4:
+broccoli-concat@^3.2.2, broccoli-concat@^3.7.1, broccoli-concat@^3.7.3, broccoli-concat@^3.7.4:
version "3.7.5"
resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.7.5.tgz#223beda8c1184252cf08ae020a3d45ffa6a48218"
integrity sha512-rDs1Mej3Ej0Cy5yIO9oIQq5+BCv0opAwS2NW7M0BeCsAMeFM42Z/zacDUC6jKc5OV5wiHvGTyCPLnZkMe0h6kQ==
@@ -5331,6 +5364,18 @@ cheerio@0.22.0, cheerio@^0.22.0:
lodash.reject "^4.4.0"
lodash.some "^4.4.0"
+cheerio@^1.0.0-rc.3:
+ version "1.0.0-rc.3"
+ resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
+ integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==
+ dependencies:
+ css-select "~1.2.0"
+ dom-serializer "~0.1.1"
+ entities "~1.1.1"
+ htmlparser2 "^3.9.1"
+ lodash "^4.15.0"
+ parse5 "^3.0.1"
+
"chokidar@>=2.0.0 <4.0.0":
version "3.3.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
@@ -5894,7 +5939,7 @@ cookie@0.3.1:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
-cookie@0.4.0:
+cookie@0.4.0, cookie@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
@@ -6488,7 +6533,7 @@ dom-serializer@0:
domelementtype "^2.0.1"
entities "^2.0.0"
-dom-serializer@~0.1.0:
+dom-serializer@~0.1.0, dom-serializer@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
@@ -6941,7 +6986,7 @@ ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.10.0, ember-cli-babel@^6.11.0,
ember-cli-version-checker "^2.1.2"
semver "^5.5.0"
-ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.0, ember-cli-babel@^7.1.2, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.10.0, ember-cli-babel@^7.11.0, ember-cli-babel@^7.12.0, ember-cli-babel@^7.13.0, ember-cli-babel@^7.13.2, ember-cli-babel@^7.17.2, ember-cli-babel@^7.18.0, ember-cli-babel@^7.19.0, ember-cli-babel@^7.7.3, ember-cli-babel@^7.9.0:
+ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.0, ember-cli-babel@^7.1.2, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.10.0, ember-cli-babel@^7.11.0, ember-cli-babel@^7.11.1, ember-cli-babel@^7.12.0, ember-cli-babel@^7.13.0, ember-cli-babel@^7.13.2, ember-cli-babel@^7.17.2, ember-cli-babel@^7.18.0, ember-cli-babel@^7.19.0, ember-cli-babel@^7.7.3, ember-cli-babel@^7.9.0:
version "7.19.0"
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.19.0.tgz#e6eddea18a867231fcf90a80689e92b98be9a63b"
integrity sha512-HiWKuoyy35vGEr+iCw6gUnQ3pS5qslyTlKEDW8cVoMbvZNGYBgRxHed5nklVUh+BS74AwR9lsp25BTAagYAP9Q==
@@ -7052,6 +7097,30 @@ ember-cli-deploy@^1.0.2:
rsvp "^3.3.3"
silent-error "^1.0.0"
+ember-cli-fastboot@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ember-cli-fastboot/-/ember-cli-fastboot-2.2.1.tgz#8c646fe3f93331c61ba87149cfecf327de79826f"
+ integrity sha512-veT089wHsYNyx+IZyjG38+RMzHiiLNX2zwRAmv31VWT1NyaEcHv7+u9iOV3KdA1wVgpicJQ2PVIOw8OuIHo+1A==
+ dependencies:
+ broccoli-concat "^3.7.1"
+ broccoli-file-creator "^2.1.1"
+ broccoli-funnel "^2.0.1"
+ broccoli-merge-trees "^3.0.1"
+ broccoli-plugin "^1.3.1"
+ chalk "^2.4.1"
+ cheerio "^1.0.0-rc.3"
+ ember-cli-babel "^7.1.0"
+ ember-cli-lodash-subset "2.0.1"
+ ember-cli-preprocess-registry "^3.1.2"
+ ember-cli-version-checker "^3.0.0"
+ fastboot "^2.0.0"
+ fastboot-express-middleware "^2.0.0"
+ fastboot-transform "^0.1.3"
+ fs-extra "^7.0.0"
+ json-stable-stringify "^1.0.1"
+ md5-hex "^2.0.0"
+ silent-error "^1.1.0"
+
ember-cli-get-component-path-option@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771"
@@ -7121,7 +7190,7 @@ ember-cli-is-package-missing@^1.0.0:
resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390"
integrity sha1-bmGEyvuSY13ZPKbJRrEEKS1OM5A=
-ember-cli-lodash-subset@^2.0.1:
+ember-cli-lodash-subset@2.0.1, ember-cli-lodash-subset@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2"
integrity sha1-IMtop5D+D94kiN39jvu332/nZvI=
@@ -7174,7 +7243,7 @@ ember-cli-postcss@^6.0.0:
ember-cli-babel "^7.1.0"
merge "^1.2.0"
-ember-cli-preprocess-registry@^3.3.0:
+ember-cli-preprocess-registry@^3.1.2, ember-cli-preprocess-registry@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.3.0.tgz#685837a314fbe57224bd54b189f4b9c23907a2de"
integrity sha512-60GYpw7VPeB7TvzTLZTuLTlHdOXvayxjAQ+IxM2T04Xkfyu75O2ItbWlftQW7NZVGkaCsXSRAmn22PG03VpLMA==
@@ -7184,6 +7253,17 @@ ember-cli-preprocess-registry@^3.3.0:
debug "^3.0.1"
process-relative-require "^1.0.0"
+ember-cli-requestanimationframe-polyfill@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/ember-cli-requestanimationframe-polyfill/-/ember-cli-requestanimationframe-polyfill-0.0.1.tgz#d5531f50d8867b7243d9a85ab9441a0588cf705c"
+ integrity sha512-zm2rLTY8EWgg5eaQ1z/yehvaonrXiEl7R0V/BEUR9PxFUdXnd3dx6cc694LKXj7puH7XUyaWeYM4pLgkhEn+MQ==
+ dependencies:
+ broccoli-funnel "^2.0.1"
+ caniuse-api "^3.0.0"
+ ember-cli-babel "^6.16.0"
+ fastboot-transform "^0.1.3"
+ raf-polyfill "^1.0.0"
+
ember-cli-sass@10.0.1:
version "10.0.1"
resolved "https://registry.yarnpkg.com/ember-cli-sass/-/ember-cli-sass-10.0.1.tgz#afa91eb7dfe3890be0390639d66976512e7d8edc"
@@ -7512,6 +7592,16 @@ ember-concurrency-decorators@^1.0.0:
ember-compatibility-helpers "^1.2.0"
ember-maybe-import-regenerator "^0.1.6"
+ember-css-transitions@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ember-css-transitions/-/ember-css-transitions-1.0.1.tgz#b846c682cefbd3a7a42a5e7a9346dbe07fb5e47e"
+ integrity sha512-XQEi/Wt++JMg5XuyTswcqRAOgDaTJPGKGjv608r7V9Sv6D+yG/9tXrqV6fi8T3wyTXcwd65Z1I+pySCPCCFyFQ==
+ dependencies:
+ ember-cli-babel "^7.18.0"
+ ember-cli-htmlbars "^4.2.3"
+ ember-cli-requestanimationframe-polyfill "^0.0.1"
+ ember-modifier "^1.0.3"
+
"ember-data@2.x - 3.x":
version "3.17.0"
resolved "https://registry.yarnpkg.com/ember-data/-/ember-data-3.17.0.tgz#724eaacd1ee43b1766a77b52e4b5a43a309a2d26"
@@ -7581,6 +7671,16 @@ ember-fetch@^6.7.1:
node-fetch "^2.6.0"
whatwg-fetch "^3.0.0"
+ember-focus-trap@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/ember-focus-trap/-/ember-focus-trap-0.4.0.tgz#b69a3a65a49784e2b3a19082655a585cfdaad473"
+ integrity sha512-NHKjTS1xoSS+fURDhAp5oyR7ZTTBnC4KVGw/VlUbFolx7jdLCePHuQdhnrhT02B1VP1dlX2RxnNvNiT2IcoA1w==
+ dependencies:
+ ember-auto-import "^1.5.3"
+ ember-cli-babel "^7.18.0"
+ ember-modifier-manager-polyfill "^1.2.0"
+ focus-trap "^5.1.0"
+
ember-get-config@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/ember-get-config/-/ember-get-config-0.2.4.tgz#118492a2a03d73e46004ed777928942021fe1ecd"
@@ -7663,7 +7763,7 @@ ember-modal-dialog@^3.0.0-beta.4:
ember-ignore-children-helper "^1.0.1"
ember-wormhole "^0.5.5"
-ember-modifier-manager-polyfill@^1.1.0:
+ember-modifier-manager-polyfill@^1.1.0, ember-modifier-manager-polyfill@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/ember-modifier-manager-polyfill/-/ember-modifier-manager-polyfill-1.2.0.tgz#cf4444e11a42ac84f5c8badd85e635df57565dda"
integrity sha512-bnaKF1LLKMkBNeDoetvIJ4vhwRPKIIumWr6dbVuW6W6p4QV8ZiO+GdF8J7mxDNlog9CeL9Z/7wam4YS86G8BYA==
@@ -7672,6 +7772,17 @@ ember-modifier-manager-polyfill@^1.1.0:
ember-cli-version-checker "^2.1.2"
ember-compatibility-helpers "^1.2.0"
+ember-modifier@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/ember-modifier/-/ember-modifier-1.0.3.tgz#ab18250666aad17c0d9170feb178e954148eb4ed"
+ integrity sha512-vWuFyvdkULUyasvEXxe5lcfuPZV/Uqe+b0IQ1yU+TY1RSJnFdVUu/CVHT8Bu4HUJInqzAihwPMTwty7fypzi5Q==
+ dependencies:
+ ember-cli-babel "^7.11.1"
+ ember-cli-is-package-missing "^1.0.0"
+ ember-cli-normalize-entity-name "^1.0.0"
+ ember-cli-string-utils "^1.1.0"
+ ember-modifier-manager-polyfill "^1.2.0"
+
ember-named-arguments-polyfill@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ember-named-arguments-polyfill/-/ember-named-arguments-polyfill-1.0.0.tgz#0b81fb81a7cef2c89e9e1d0278b579e708bf4ded"
@@ -7790,10 +7901,10 @@ ember-source-channel-url@^2.0.1:
dependencies:
got "^8.0.1"
-ember-source@^3.17.2, ember-source@~3.17.2:
- version "3.17.2"
- resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.17.2.tgz#9732ff0786034a1195b3ba250f671e7939cabbce"
- integrity sha512-evoOkJp9wsxTndR4hVYH5jEN7SlsYtjrG58TELGG6aVim+7nM2bidNGO011f0c+1aI67blqmejmoS/MhfLfNRA==
+ember-source@^3.17.3, ember-source@~3.17.3:
+ version "3.17.3"
+ resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.17.3.tgz#315b198848bcc1699928579b2d7fc2d607ebf63e"
+ integrity sha512-mZ2a4MRJm+QsZ61q7p4Ulq+07IERgEF7mEzOPmqES+J4PpeXyWHAYh1MnSWHz3W5jQhwHQAPs6WTZE0TbAsS2Q==
dependencies:
"@babel/helper-module-imports" "^7.8.3"
"@babel/plugin-transform-block-scoping" "^7.8.3"
@@ -8651,6 +8762,15 @@ fast-sourcemap-concat@^1.4.0:
source-map-url "^0.3.0"
sourcemap-validator "^1.1.0"
+fastboot-express-middleware@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fastboot-express-middleware/-/fastboot-express-middleware-2.0.0.tgz#3cb2c4b744e738a709b4336c4166f1a059ab0ffb"
+ integrity sha512-sJHZrHpo/8jh56t+DTzaDcg6cnHbmXlTSAdfhRZbBa8XDY3TfN+TjHsHd4Z7vouLFU+ISuaZkzKfwGwipW5xwQ==
+ dependencies:
+ chalk "^2.0.1"
+ fastboot "^2.0.1"
+ request "^2.81.0"
+
fastboot-transform@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/fastboot-transform/-/fastboot-transform-0.1.3.tgz#7dea0b117594afd8772baa6c9b0919644e7f7dcd"
@@ -8659,6 +8779,20 @@ fastboot-transform@^0.1.3:
broccoli-stew "^1.5.0"
convert-source-map "^1.5.1"
+fastboot@^2.0.0, fastboot@^2.0.1:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/fastboot/-/fastboot-2.0.3.tgz#0b712e6c590f1b463dc5b12138893bcbbafa2459"
+ integrity sha512-NNH/o+XhITAQUnW2CC9IDXlcnI74W2BONjtRSRmc01N3uJl/7pcvX9iWTUWu2PYQbQZUBu8HzVFt7GmQ9qw9JQ==
+ dependencies:
+ chalk "^2.0.1"
+ cookie "^0.4.0"
+ debug "^4.1.0"
+ najax "^1.0.3"
+ resolve "^1.8.1"
+ rsvp "^4.8.0"
+ simple-dom "^1.4.0"
+ source-map-support "^0.5.0"
+
fastq@^1.6.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.7.0.tgz#fcd79a08c5bd7ec5b55cd3f5c4720db551929801"
@@ -8868,10 +9002,18 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
-focus-visible@^5.0.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.0.2.tgz#4fae9cf40458b73c10701c9774c462e3ccd53caf"
- integrity sha512-zT2fj/bmOgEBjqGbURGlowTmCwsIs3bRDMr/sFZz8Ly7VkEiwuCn9swNTL3pPuf8Oua2de7CLuKdnuNajWdDsQ==
+focus-trap@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-5.1.0.tgz#64a0bfabd95c382103397dbc96bfef3a3cf8e5ad"
+ integrity sha512-CkB/nrO55069QAUjWFBpX6oc+9V90Qhgpe6fBWApzruMq5gnlh90Oo7iSSDK7pKiV5ugG6OY2AXM5mxcmL3lwQ==
+ dependencies:
+ tabbable "^4.0.0"
+ xtend "^4.0.1"
+
+focus-visible@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.1.0.tgz#4b9d40143b865f53eafbd93ca66672b3bf9e7b6a"
+ integrity sha512-nPer0rjtzdZ7csVIu233P2cUm/ks/4aVSI+5KUkYrYpgA7ujgC3p6J7FtFU+AIMWwnwYQOB/yeiOITxFeYIXiw==
follow-redirects@^1.0.0:
version "1.11.0"
@@ -10496,6 +10638,11 @@ joi@^12.0.0:
isemail "3.x.x"
topo "2.x.x"
+jquery-deferred@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/jquery-deferred/-/jquery-deferred-0.3.1.tgz#596eca1caaff54f61b110962b23cafea74c35355"
+ integrity sha1-WW7KHKr/VPYbEQlisjyv6nTDU1U=
+
jquery@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2"
@@ -11206,7 +11353,7 @@ lodash@^3.10.0:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
-lodash@^4.0.0, lodash@^4.1.0, lodash@^4.17.10, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.5.1, lodash@^4.6.1:
+lodash@^4.0.0, lodash@^4.1.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.5.1, lodash@^4.6.1:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -11431,6 +11578,18 @@ matcher-collection@^2.0.0:
"@types/minimatch" "^3.0.3"
minimatch "^3.0.2"
+md5-hex@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-2.0.0.tgz#d0588e9f1c74954492ecd24ac0ac6ce997d92e33"
+ integrity sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=
+ dependencies:
+ md5-o-matic "^0.1.1"
+
+md5-o-matic@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3"
+ integrity sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=
+
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -11860,6 +12019,15 @@ mz@^2.5.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
+najax@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/najax/-/najax-1.0.4.tgz#63fd8dbf15d18f24dc895b3a16fec66c136b8084"
+ integrity sha512-wsSacA+RkgY1wxRxXCT3tdqzmamEv9PLeoV/ub9SlLf2RngbPMSqc3A7H35XJDfURC0twMmZsnPdsYPkuuFSVg==
+ dependencies:
+ jquery-deferred "^0.3.0"
+ lodash.defaultsdeep "^4.6.0"
+ qs "^6.2.0"
+
nan@^2.12.1:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
@@ -12644,6 +12812,13 @@ parse5@^1.5.1:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
integrity sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=
+parse5@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
+ integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==
+ dependencies:
+ "@types/node" "*"
+
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
@@ -13147,7 +13322,7 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
-qs@^6.4.0:
+qs@^6.2.0, qs@^6.4.0:
version "6.9.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e"
integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==
@@ -13214,6 +13389,11 @@ qunit@^2.9.3:
node-watch "0.6.1"
resolve "1.9.0"
+raf-polyfill@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/raf-polyfill/-/raf-polyfill-1.0.0.tgz#cc6019be5bbb7112b8eeaae0ea8b5077100802e2"
+ integrity sha512-WwyjuX5kZFOslF+8mGjVrMvDYmOwlN50Eqoc876td1abMaesf1sK4uiOZor3bvJfBRCwCHuJNR3TN4KztC/IhA==
+
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -13613,7 +13793,7 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.7:
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
-request@^2.55.0, request@^2.88.0:
+request@^2.55.0, request@^2.81.0, request@^2.88.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
@@ -13867,7 +14047,7 @@ rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a"
integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==
-rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3, rsvp@^4.8.4, rsvp@^4.8.5:
+rsvp@^4.7.0, rsvp@^4.8.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3, rsvp@^4.8.4, rsvp@^4.8.5:
version "4.8.5"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
@@ -14134,6 +14314,17 @@ silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0, silent-error@^1.1
dependencies:
debug "^2.2.0"
+simple-dom@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/simple-dom/-/simple-dom-1.4.0.tgz#78ad1f41b8b70d16f82b7e0d458441c9262565b7"
+ integrity sha512-TnBPkmOyjdaOqyBMb4ick+n8c0Xv9Iwg1PykFV7hz9Se3UCiacTbRb+25cPmvozFNJLBUNvUzX/KsPfXF14ivA==
+ dependencies:
+ "@simple-dom/document" "^1.4.0"
+ "@simple-dom/interface" "^1.4.0"
+ "@simple-dom/parser" "^1.4.0"
+ "@simple-dom/serializer" "^1.4.0"
+ "@simple-dom/void-map" "^1.4.0"
+
simple-html-tokenizer@^0.5.8, simple-html-tokenizer@^0.5.9:
version "0.5.9"
resolved "https://registry.yarnpkg.com/simple-html-tokenizer/-/simple-html-tokenizer-0.5.9.tgz#1a83fe97f5a3e39b335fddf71cfe9b0263b581c2"
@@ -14349,7 +14540,7 @@ source-map-support@^0.4.15:
dependencies:
source-map "^0.5.6"
-source-map-support@~0.5.12:
+source-map-support@^0.5.0, source-map-support@~0.5.12:
version "0.5.16"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
@@ -14818,6 +15009,11 @@ sync-disk-cache@^1.3.3:
rimraf "^2.2.8"
username-sync "^1.0.2"
+tabbable@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261"
+ integrity sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ==
+
table@^5.2.3:
version "5.4.6"
resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
@@ -16033,7 +16229,7 @@ xmlhttprequest-ssl@~1.5.4:
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
-xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
+xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==