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 @@ + + +
+ + Title + +

Some contents...

+

Some contents...

+

Some contents...

+
+ + + + +
+
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 @@ + 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 @@ + + + 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 @@ + + +
+ + Title + +

Some contents...

+

Some contents...

+

Some contents...

+
+ + + + +
+
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 + + + `; + + 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==