diff --git a/addons/rose/addon/components/rose/header.js b/addons/rose/addon/components/rose/header.js new file mode 100644 index 000000000..0eb922549 --- /dev/null +++ b/addons/rose/addon/components/rose/header.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../templates/components/rose/header'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/header.stories.mdx b/addons/rose/addon/components/rose/header.stories.mdx new file mode 100644 index 000000000..05d376e64 --- /dev/null +++ b/addons/rose/addon/components/rose/header.stories.mdx @@ -0,0 +1,72 @@ +import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; +import { hbs } from 'ember-cli-htmlbars'; +import { action } from '@storybook/addon-actions'; +import { text, boolean } from '@storybook/addon-knobs'; + + + +# Header + +A header component that allows three distinct sections to be configured: brand, navigation, and utilities. + +```htmlbars + + + + + + Org name + + link + button + + + Section + + + + + Click me + + link + button + + + + +``` + + + {{ + template: hbs` + + + + + {{navigation-dropdown-label}} + + {{navigation-dropdown-link-label}} + {{navigation-dropdown-button-label}} + + + {{navigation-link-label}} + + + + + + link + button + + + + + `, + context: { + 'navigation-dropdown-label': text('navigation-dropdown-label', 'Org Name'), + 'navigation-dropdown-link-label': text('navigation-dropdown-link-label', 'Menu Item'), + 'navigation-dropdown-button-label': text('navigation-dropdown-button-label', 'Menu Item'), + 'navigation-link-label': text('navigation-link-label', 'Section'), + }, + }} + diff --git a/addons/rose/addon/components/rose/header/brand.js b/addons/rose/addon/components/rose/header/brand.js new file mode 100644 index 000000000..c1e63e6ab --- /dev/null +++ b/addons/rose/addon/components/rose/header/brand.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/header/brand'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/header/dropdown.js b/addons/rose/addon/components/rose/header/dropdown.js new file mode 100644 index 000000000..4a5897084 --- /dev/null +++ b/addons/rose/addon/components/rose/header/dropdown.js @@ -0,0 +1,16 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/header/dropdown'; +import { action } from '@ember/object'; + +export default Component.extend({ + layout, + tagName: '', + + // Uses details widget state to close dropdown + @action + close(element) { + if (element.open) { + element.open = false; + } + }, +}); diff --git a/addons/rose/addon/components/rose/header/dropdown/content.js b/addons/rose/addon/components/rose/header/dropdown/content.js new file mode 100644 index 000000000..4f2bf32a0 --- /dev/null +++ b/addons/rose/addon/components/rose/header/dropdown/content.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../../templates/components/rose/header/dropdown/content'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/header/dropdown/content/button.js b/addons/rose/addon/components/rose/header/dropdown/content/button.js new file mode 100644 index 000000000..fa19bd4b9 --- /dev/null +++ b/addons/rose/addon/components/rose/header/dropdown/content/button.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../../../templates/components/rose/header/dropdown/content/button'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/header/dropdown/trigger.js b/addons/rose/addon/components/rose/header/dropdown/trigger.js new file mode 100644 index 000000000..72ffb581c --- /dev/null +++ b/addons/rose/addon/components/rose/header/dropdown/trigger.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../../templates/components/rose/header/dropdown/trigger'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/header/navigation.js b/addons/rose/addon/components/rose/header/navigation.js new file mode 100644 index 000000000..4ef10f9e3 --- /dev/null +++ b/addons/rose/addon/components/rose/header/navigation.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/header/navigation'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/header/utilities.js b/addons/rose/addon/components/rose/header/utilities.js new file mode 100644 index 000000000..ff615c434 --- /dev/null +++ b/addons/rose/addon/components/rose/header/utilities.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/header/utilities'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/modifiers/on-click-outside.js b/addons/rose/addon/modifiers/on-click-outside.js new file mode 100644 index 000000000..8feb0335e --- /dev/null +++ b/addons/rose/addon/modifiers/on-click-outside.js @@ -0,0 +1,15 @@ +import { modifier } from 'ember-modifier'; + +export default modifier((element, [callback]) => { + function handleClick(event) { + if (!element.contains(event.target)) { + callback(element, event); + } + } + + document.addEventListener('click', handleClick, false); + + return () => { + document.removeEventListener('click', handleClick, false); + }; +}); diff --git a/addons/rose/addon/styles/rose/components/_header.scss b/addons/rose/addon/styles/rose/components/_header.scss new file mode 100644 index 000000000..fb9787b99 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/_header.scss @@ -0,0 +1,168 @@ +@use '../variables/sizing'; +@use '../variables/media'; +@use '../utilities/type'; + +$brand-hashicorp: "data:image/svg+xml;utf-8,"; + +$dropdown-chevron: ( + 'default': + "data:image/svg+xml;utf-8,", + 'open': + "data:image/svg+xml;utf-8,", +); + +.rose-header { + @include type.type(s, semibold); + display: grid; + grid-template-areas: 'brand navigation utilities'; + grid-template-columns: 0.01fr auto 1fr; + grid-gap: sizing.rems(xxxs); + background: var(--black); + color: var(--white); + + .rose-header-brand { + grid-area: brand; + width: sizing.rems(l); + height: sizing.rems(l); + background-image: url($brand-hashicorp); + background-repeat: no-repeat; + margin: sizing.rems(xxs); + } + + .rose-header-navigation { + grid-area: navigation; + + .rose-header-navigation-flex { + display: flex; + flex-wrap: wrap; + } + + .rose-header-navigation-link { + text-decoration: none; + display: block; + color: var(--white); + border: 1px solid var(--stark); + border-radius: sizing.rems(xxs); + text-align: center; + padding: sizing.rems(xxs) sizing.rems(s); + position: relative; + top: sizing.rems(xxxs); + cursor: pointer; + margin: 0 sizing.rems(xs); + + &:hover { + background: var(--ui-gray-starker-3); + } + + &:active { + background: var(--ui-gray-starker-2); + } + } + } + + .rose-header-utilities { + grid-area: utilities; + + .rose-header-utilities-flex { + margin-right: sizing.rems(s); + display: flex; + flex-wrap: wrap; + flex-direction: row-reverse; + } + } + + .rose-header-navigation, + .rose-header-utilities { + .rose-header-dropdown { + &[open] { + .rose-header-dropdown-trigger { + background: var(--white); + color: var(--ui-gray-starker-4); + + .rose-header-dropdown-chevron { + background-image: url(map-get($dropdown-chevron, 'open')); + } + } + } + + .rose-header-dropdown-trigger { + padding: sizing.rems(xxs) sizing.rems(s); + border-radius: sizing.rems(xxxs); + color: var(--white); + position: relative; + top: sizing.rems(xxxs); + cursor: pointer; + &::-webkit-details-marker { + display: none; + } + + .rose-header-dropdown-chevron { + background-image: url(map-get($dropdown-chevron, 'default')); + width: sizing.rems(m); + height: sizing.rems(m); + background-repeat: no-repeat; + display: inline-block; + vertical-align: middle; + } + } + + .rose-header-dropdown-content { + position: absolute; + background-color: var(--white); + border-radius: sizing.rems(xxxs); + border: 1px solid var(--ui-gray-subtler-2); + padding-right: sizing.rems(xl); + margin-top: sizing.rems(xxxs); + + &.rose-header-dropdown-content-right { + right: sizing.rems(s); + } + + .rose-header-dropdown-content-link { + padding: sizing.rems(xs) sizing.rems(s); + text-decoration: none; + display: block; + color: var(--ui-gray-starker-4); + height: sizing.rems(l); + } + + .rose-header-dropdown-content-button { + button { + cursor: pointer; + padding: sizing.rems(xs) sizing.rems(s); + color: var(--ui-gray-starker-4); + display: inline-block; + border: none; + text-decoration: none; + font-size: inherit; + font-weight: inherit; + -webkit-appearance: none; + } + } + } + } + } +} + +@media (max-width: media.width(small)) { + .rose-header { + grid-template-columns: 1fr 3fr; + grid-template-areas: + 'brand utilities' + 'navigation navigation'; + padding-bottom: 0; + + .rose-header-navigation { + background: var(--ui-header-subtler); + padding: sizing.rems(xs) sizing.rems(s); + + .rose-header-navigation-link { + border: 1px solid var(--ui-gray-subtler); + + &:hover { + background: var(--ui-gray-starker-3); + } + } + } + } +} diff --git a/addons/rose/addon/styles/rose/components/_index.scss b/addons/rose/addon/styles/rose/components/_index.scss index dd972080b..475417601 100644 --- a/addons/rose/addon/styles/rose/components/_index.scss +++ b/addons/rose/addon/styles/rose/components/_index.scss @@ -1,2 +1,3 @@ @import 'button'; @import 'form'; +@import 'header'; diff --git a/addons/rose/addon/styles/rose/variables/_index.scss b/addons/rose/addon/styles/rose/variables/_index.scss index 0f1c38707..c789019f7 100644 --- a/addons/rose/addon/styles/rose/variables/_index.scss +++ b/addons/rose/addon/styles/rose/variables/_index.scss @@ -2,3 +2,4 @@ @import 'typography'; @import 'color'; @import 'opacity'; +@import 'media'; diff --git a/addons/rose/addon/styles/rose/variables/_media.scss b/addons/rose/addon/styles/rose/variables/_media.scss new file mode 100644 index 000000000..289c96ad9 --- /dev/null +++ b/addons/rose/addon/styles/rose/variables/_media.scss @@ -0,0 +1,21 @@ +@use 'sass:map'; + +/** + * SASS variables various media query sizes + */ + +$width-breakpoints: ( + xxlarge: 1440px, + xlarge: 1200px, + large: 1024px, + medium: 768px, + small: 480px, + xsmall: 320px, +); + +/** + * Returns a media width variable. + */ +@function width($name) { + @return map.get($width-breakpoints, $name); +} diff --git a/addons/rose/addon/styles/rose/variables/color/_css.scss b/addons/rose/addon/styles/rose/variables/color/_css.scss index 765b71ac7..ca6df5c3d 100644 --- a/addons/rose/addon/styles/rose/variables/color/_css.scss +++ b/addons/rose/addon/styles/rose/variables/color/_css.scss @@ -74,6 +74,8 @@ --ui-gray-starker-2: #{color(ui-gray, 700)}; --ui-gray-starker-3: #{color(ui-gray, 800)}; --ui-gray-starker-4: #{color(ui-gray, 900)}; + + --ui-header-subtler: #{color(ui-cool-gray, 700)}; } // Dark Mode @@ -131,5 +133,7 @@ --ui-gray-starker-2: #{color(ui-gray, 100)}; --ui-gray-starker-3: #{color(ui-gray, 050)}; --ui-gray-starker-4: #{color(ui-gray, 010)}; + + --ui-header-subtler: #{color(ui-cool-gray, 100)}; } } diff --git a/addons/rose/addon/templates/components/rose/header.hbs b/addons/rose/addon/templates/components/rose/header.hbs new file mode 100644 index 000000000..343b45d93 --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header.hbs @@ -0,0 +1,8 @@ +
+ {{yield (hash + brand=(component 'rose/header/brand') + utilities=(component 'rose/header/utilities') + navigation=(component 'rose/header/navigation') + )}} +
diff --git a/addons/rose/addon/templates/components/rose/header/brand.hbs b/addons/rose/addon/templates/components/rose/header/brand.hbs new file mode 100644 index 000000000..836e22b70 --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header/brand.hbs @@ -0,0 +1 @@ + diff --git a/addons/rose/addon/templates/components/rose/header/dropdown.hbs b/addons/rose/addon/templates/components/rose/header/dropdown.hbs new file mode 100644 index 000000000..3f4810eea --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header/dropdown.hbs @@ -0,0 +1,8 @@ +
+ + {{yield (hash + trigger=(component 'rose/header/dropdown/trigger') + content=(component 'rose/header/dropdown/content' alignRight=@alignRight) + )}} +
diff --git a/addons/rose/addon/templates/components/rose/header/dropdown/content.hbs b/addons/rose/addon/templates/components/rose/header/dropdown/content.hbs new file mode 100644 index 000000000..68af8036a --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header/dropdown/content.hbs @@ -0,0 +1,6 @@ + + {{yield (hash + link=(component 'link-to' class="rose-header-dropdown-content-link") + button=(component 'rose/header/dropdown/content/button') + )}} + diff --git a/addons/rose/addon/templates/components/rose/header/dropdown/content/button.hbs b/addons/rose/addon/templates/components/rose/header/dropdown/content/button.hbs new file mode 100644 index 000000000..e437e4689 --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header/dropdown/content/button.hbs @@ -0,0 +1,3 @@ + + + diff --git a/addons/rose/addon/templates/components/rose/header/dropdown/trigger.hbs b/addons/rose/addon/templates/components/rose/header/dropdown/trigger.hbs new file mode 100644 index 000000000..f513aa8bd --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header/dropdown/trigger.hbs @@ -0,0 +1,4 @@ + + {{yield}} + + diff --git a/addons/rose/addon/templates/components/rose/header/navigation.hbs b/addons/rose/addon/templates/components/rose/header/navigation.hbs new file mode 100644 index 000000000..9e2b4308b --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header/navigation.hbs @@ -0,0 +1,8 @@ + + + {{yield (hash + link=(component 'link-to' class="rose-header-navigation-link") + dropdown=(component 'rose/header/dropdown') + )}} + + diff --git a/addons/rose/addon/templates/components/rose/header/utilities.hbs b/addons/rose/addon/templates/components/rose/header/utilities.hbs new file mode 100644 index 000000000..eefb15e8d --- /dev/null +++ b/addons/rose/addon/templates/components/rose/header/utilities.hbs @@ -0,0 +1,7 @@ + + + {{yield (hash + dropdown=(component 'rose/header/dropdown' position="true") + )}} + + diff --git a/addons/rose/app/components/rose/header.js b/addons/rose/app/components/rose/header.js new file mode 100644 index 000000000..7c011982b --- /dev/null +++ b/addons/rose/app/components/rose/header.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header'; diff --git a/addons/rose/app/components/rose/header/brand.js b/addons/rose/app/components/rose/header/brand.js new file mode 100644 index 000000000..edd708f53 --- /dev/null +++ b/addons/rose/app/components/rose/header/brand.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header/brand'; diff --git a/addons/rose/app/components/rose/header/dropdown.js b/addons/rose/app/components/rose/header/dropdown.js new file mode 100644 index 000000000..16d89ac10 --- /dev/null +++ b/addons/rose/app/components/rose/header/dropdown.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header/dropdown'; diff --git a/addons/rose/app/components/rose/header/dropdown/content.js b/addons/rose/app/components/rose/header/dropdown/content.js new file mode 100644 index 000000000..51792f92e --- /dev/null +++ b/addons/rose/app/components/rose/header/dropdown/content.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header/dropdown/content'; diff --git a/addons/rose/app/components/rose/header/dropdown/content/button.js b/addons/rose/app/components/rose/header/dropdown/content/button.js new file mode 100644 index 000000000..cc70f39b5 --- /dev/null +++ b/addons/rose/app/components/rose/header/dropdown/content/button.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header/dropdown/content/button'; diff --git a/addons/rose/app/components/rose/header/dropdown/trigger.js b/addons/rose/app/components/rose/header/dropdown/trigger.js new file mode 100644 index 000000000..0bb1491ed --- /dev/null +++ b/addons/rose/app/components/rose/header/dropdown/trigger.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header/dropdown/trigger'; diff --git a/addons/rose/app/components/rose/header/navigation.js b/addons/rose/app/components/rose/header/navigation.js new file mode 100644 index 000000000..ff5cfc74a --- /dev/null +++ b/addons/rose/app/components/rose/header/navigation.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header/navigation'; diff --git a/addons/rose/app/components/rose/header/utilities.js b/addons/rose/app/components/rose/header/utilities.js new file mode 100644 index 000000000..6c4acf7b5 --- /dev/null +++ b/addons/rose/app/components/rose/header/utilities.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/header/utilities'; diff --git a/addons/rose/app/modifiers/on-click-outside.js b/addons/rose/app/modifiers/on-click-outside.js new file mode 100644 index 000000000..845e122c1 --- /dev/null +++ b/addons/rose/app/modifiers/on-click-outside.js @@ -0,0 +1 @@ +export { default } from 'rose/modifiers/on-click-outside'; diff --git a/addons/rose/tests/unit/.gitkeep b/addons/rose/app/templates/about.hbs similarity index 100% rename from addons/rose/tests/unit/.gitkeep rename to addons/rose/app/templates/about.hbs diff --git a/addons/rose/package.json b/addons/rose/package.json index 755adec7e..bcc19b49f 100644 --- a/addons/rose/package.json +++ b/addons/rose/package.json @@ -57,6 +57,7 @@ "ember-inline-svg": "^1.0.0", "ember-load-initializers": "^2.1.1", "ember-maybe-import-regenerator": "^0.1.6", + "ember-modifier": "^1.0.3", "ember-qunit": "^4.6.0", "ember-radio-button": "^2.0.1", "ember-resolver": "^7.0.0", diff --git a/addons/rose/tests/dummy/app/router.js b/addons/rose/tests/dummy/app/router.js index 818c8d496..c5464a74c 100644 --- a/addons/rose/tests/dummy/app/router.js +++ b/addons/rose/tests/dummy/app/router.js @@ -6,4 +6,6 @@ export default class Router extends EmberRouter { rootURL = config.rootURL; } -Router.map(function () {}); +Router.map(function () { + this.route('about'); +}); diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index 0a96fc98a..6e3605e07 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -1,3 +1,29 @@ + + + + + + Org name + + link + button + + + Section + + + + + + + link + button + + + + + + Dummy app index template

Icon

diff --git a/addons/rose/tests/integration/components/rose/header-test.js b/addons/rose/tests/integration/components/rose/header-test.js new file mode 100644 index 000000000..72b6ef3fb --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header-test.js @@ -0,0 +1,58 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/header', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header')); + }); + + test('it renders with brand', async function (assert) { + await render(hbs` + + `); + assert.ok(find('.rose-header-brand')); + assert.notOk(find('.rose-header-navigation')); + assert.notOk(find('.rose-header-utilities')); + }); + + test('it renders with navigation', async function (assert) { + await render(hbs` + + `); + assert.ok(find('.rose-header-navigation')); + assert.notOk(find('.rose-header-brand')); + assert.notOk(find('.rose-header-utilities')); + }); + + test('it renders with navigation elements', async function (assert) { + await render(hbs` + + + + `); + assert.ok(find('.rose-header-navigation-link')); + }); + + test('it renders with utilities', async function (assert) { + await render(hbs` + + `); + assert.notOk(find('.rose-header-brand')); + assert.notOk(find('.rose-header-navigation')); + assert.ok(find('.rose-header-utilities')); + }); + + test('it renders with utility elements', async function (assert) { + await render(hbs` + + + + `); + assert.ok(find('.rose-header-dropdown')); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/header/brand-test.js b/addons/rose/tests/integration/components/rose/header/brand-test.js new file mode 100644 index 000000000..e3df6dc9e --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header/brand-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/header/brand', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-brand')); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/header/dropdown-test.js b/addons/rose/tests/integration/components/rose/header/dropdown-test.js new file mode 100644 index 000000000..439c29800 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header/dropdown-test.js @@ -0,0 +1,78 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, click, find, findAll } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/header/dropdown', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-dropdown')); + }); + + test('it renders with html attributes', async function (assert) { + await render( + hbs`` + ); + assert.ok(find('#custom-id')); + assert.ok(find('.custom-class')); + }); + + test('it renders with trigger', async function (assert) { + await render(hbs` + Click me + `); + assert.ok(find('.rose-header-dropdown-trigger')); + assert.equal( + find('.rose-header-dropdown-trigger').textContent.trim(), + 'Click me' + ); + }); + + test('it renders with content', async function (assert) { + await render(hbs` + + + + + + + + `); + assert.ok(find('.rose-header-dropdown-content')); + assert.equal(findAll('a').length, 2); + assert.equal(findAll('button').length, 3); + }); + + test('it is toggled on click on trigger content', async function (assert) { + await render(hbs` + Click me + + + + `); + assert.notOk(find('#dropdown').open); + + await click('#trigger'); + assert.ok(find('#dropdown').open); + + await click('#trigger'); + assert.notOk(find('#dropdown').open); + }); + + test('it is closed with outside click is triggered', async function (assert) { + await render(hbs`
+ Click me + + + +
`); + + await click('#trigger'); + assert.ok(find('#dropdown').open); + + await click('#wrapper'); + assert.notOk(find('#dropdown').open); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/header/dropdown/content-test.js b/addons/rose/tests/integration/components/rose/header/dropdown/content-test.js new file mode 100644 index 000000000..b0bb4a371 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header/dropdown/content-test.js @@ -0,0 +1,75 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/header/dropdown/content', function ( + hooks +) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-dropdown-content')); + }); + + test('it renders with content', async function (assert) { + await render(hbs` + content + `); + assert.equal( + find('.rose-header-dropdown-content').textContent.trim(), + 'content' + ); + }); + + test('it renders with html attributes', async function (assert) { + await render( + hbs`` + ); + assert.equal(find('.rose-header-dropdown-content').id, 'dropdown-content'); + assert.ok( + find('.rose-header-dropdown-content').className.match('universe') + ); + }); + + test('it is positioned right when @alignRight={{true}}', async function (assert) { + await render(hbs``); + assert.notOk(find('.rose-header-dropdown-content-right')); + + await render( + hbs`` + ); + assert.ok(find('.rose-header-dropdown-content-right')); + }); + + test('it render link element', async function (assert) { + await render(hbs` + + `); + assert.ok(find('a')); + assert.ok(find('.rose-header-dropdown-content-link')); + }); + + test('it render link element with content', async function (assert) { + await render(hbs` + linkify + `); + assert.equal(find('a').textContent.trim(), 'linkify'); + }); + + test('it render button element', async function (assert) { + await render(hbs` + + `); + assert.ok(find('button')); + assert.ok(find('.rose-header-dropdown-content-button')); + }); + + test('it render button element with content', async function (assert) { + await render(hbs` + dropdown button + `); + assert.equal(find('button').textContent.trim(), 'dropdown button'); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/header/dropdown/content/button-test.js b/addons/rose/tests/integration/components/rose/header/dropdown/content/button-test.js new file mode 100644 index 000000000..a73dc28df --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header/dropdown/content/button-test.js @@ -0,0 +1,32 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module( + 'Integration | Component | rose/header/dropdown/content/button', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-dropdown-content-button')); + }); + + test('it renders with content', async function (assert) { + await render( + hbs`Button content` + ); + assert.equal( + find('.rose-header-dropdown-content-button').textContent.trim(), + 'Button content' + ); + }); + + test('it render button element', async function (assert) { + await render(hbs``); + assert.ok(find('button')); + assert.equal(find('button').type, 'button'); + }); + } +); diff --git a/addons/rose/tests/integration/components/rose/header/dropdown/trigger-test.js b/addons/rose/tests/integration/components/rose/header/dropdown/trigger-test.js new file mode 100644 index 000000000..83309f23e --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header/dropdown/trigger-test.js @@ -0,0 +1,41 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/header/dropdown/trigger', function ( + hooks +) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-dropdown-trigger')); + assert.notOk(find('.rose-header-dropdown-open')); + }); + + test('it renders with content', async function (assert) { + await render(hbs` + trigger content + `); + assert.equal( + find('.rose-header-dropdown-trigger').textContent.trim(), + 'trigger content' + ); + }); + + test('it renders with html attributes', async function (assert) { + await render( + hbs`` + ); + assert.equal(find('.rose-header-dropdown-trigger').id, 'trigger'); + assert.ok( + find('.rose-header-dropdown-trigger').className.match('dropdown-trigger') + ); + }); + + test('it renders chevron', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-dropdown-chevron')); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/header/navigation-test.js b/addons/rose/tests/integration/components/rose/header/navigation-test.js new file mode 100644 index 000000000..11ac6cda5 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header/navigation-test.js @@ -0,0 +1,29 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find, findAll } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/header/navigation', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-navigation')); + }); + + test('it renders navigation link elements', async function (assert) { + await render(hbs` + + + `); + assert.equal(findAll('a').length, 2); + }); + + test('it renders navigation dropdown elements', async function (assert) { + await render(hbs` + + + `); + assert.equal(findAll('.rose-header-dropdown').length, 2); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/header/utilities-test.js b/addons/rose/tests/integration/components/rose/header/utilities-test.js new file mode 100644 index 000000000..b0dca161d --- /dev/null +++ b/addons/rose/tests/integration/components/rose/header/utilities-test.js @@ -0,0 +1,21 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find, findAll } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/header/utilities', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-header-utilities')); + }); + + test('it renders navigation dropdown elements', async function (assert) { + await render(hbs` + + + `); + assert.equal(findAll('.rose-header-dropdown').length, 2); + }); +}); diff --git a/addons/rose/tests/integration/modifiers/on-click-outside-test.js b/addons/rose/tests/integration/modifiers/on-click-outside-test.js new file mode 100644 index 000000000..7318ef423 --- /dev/null +++ b/addons/rose/tests/integration/modifiers/on-click-outside-test.js @@ -0,0 +1,36 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, click } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Modifier | on-click-outside', function (hooks) { + setupRenderingTest(hooks); + + test('it fires event when an outside element is clicked', async function (assert) { + this.set('clickedOutside', (element, event) => { + assert.ok(element); + assert.equal(event.target.id, 'outside'); + }); + + await render(hbs`
+
`); + + await click('#outside'); + }); + + test('it does not fire event when element is clicked', async function (assert) { + assert.expect(1); + this.set('clickedOutside', () => { + assert.ok(true); + }); + + await render(hbs`
+
+
+
`); + + await click('#inside'); + await click('#item'); + await click('#outside'); + }); +}); diff --git a/yarn.lock b/yarn.lock index e888e5e7a..99c5c4865 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2470,9 +2470,9 @@ integrity sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A== "@types/node@^9.6.0": - version "9.6.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.55.tgz#7cc1358c9c18e71f6c020e410962971863232cf5" - integrity sha512-e/5tg8Ok0gSrN6pvHphnwTK0/CD9VPZrtZqpvvpEFAtfs+ZntusgGaWkf2lSEq1OFe2EDPeUMiMVpy4nZpJ4AQ== + version "9.6.56" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.56.tgz#036f665320d2f04bd62c0cd83222254a6a3b4437" + integrity sha512-Cq4pUCsBL6H7X0HFAOap75lmQqcnSmUDSP0R03lz9UsxRvBu5QsnKLLgIoitlFBX+j6LmciWYQAbOSmGMi7vwA== "@types/npmlog@^4.1.2": version "4.1.2" @@ -3844,6 +3844,13 @@ babel-plugin-ember-modules-api-polyfill@^2.12.0, babel-plugin-ember-modules-api- dependencies: ember-rfc176-data "^0.3.12" +babel-plugin-ember-modules-api-polyfill@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.13.0.tgz#f9d3928d4c40192a44a5b52b67bbdedc4a748ea2" + integrity sha512-Q2i7uZMNSuJFYUV8stEsLQIRfMhQJew62sOnR+ESNjb4vlI7Rj1JlSgymTGwmCTVh+poTBpMidiWCoITDtbiIA== + dependencies: + ember-rfc176-data "^0.3.13" + babel-plugin-emotion@^10.0.20, babel-plugin-emotion@^10.0.27: version "10.0.33" resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz#ce1155dcd1783bbb9286051efee53f4e2be63e03" @@ -4896,23 +4903,21 @@ broccoli-funnel-reducer@^1.0.0: resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" integrity sha1-ETZbKnha7JsXlyo234fu8kxcwOo= -broccoli-funnel@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-3.0.0.tgz#46fa8b570eccdfa9f66c71e85ce4a5dc68ec2ad6" - integrity sha512-BzqVvCXQt/d0Lk9fmT8Z/34rt2BB1OjQe1+e5w29ZXkg7pBlvRIYiPq3M+1Hy0E6jJ/ASB6m/d7TBl7cTHjEFQ== +broccoli-funnel@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-3.0.3.tgz#26fd42632471f67a91f4770d1987118087219937" + integrity sha512-LPzZ91BwStoHZXdXHQAJeYORl189OrRKM5NdIi86SDU9wZ4s/3lV1PRFOiobDT/jKM10voM7CDzfvicHbCYxAQ== dependencies: array-equal "^1.0.0" blank-object "^1.0.1" - broccoli-plugin "^3.0.0" + broccoli-plugin "^4.0.1" debug "^4.1.1" fast-ordered-set "^1.0.0" fs-tree-diff "^2.0.1" heimdalljs "^0.2.0" minimatch "^3.0.0" path-posix "^1.0.0" - rimraf "^3.0.0" - symlink-or-copy "^1.0.0" - walk-sync "^0.3.1" + walk-sync "^2.0.2" broccoli-funnel@^1.0.1: version "1.2.0" @@ -5175,7 +5180,7 @@ broccoli-plugin@^2.0.0, broccoli-plugin@^2.1.0: rimraf "^2.3.4" symlink-or-copy "^1.1.8" -broccoli-plugin@^3.0.0, broccoli-plugin@^3.1.0: +broccoli-plugin@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz#54ba6dd90a42ec3db5624063292610e326b1e542" integrity sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA== @@ -5694,9 +5699,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0: - version "1.0.30001061" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001061.tgz#80ca87ef14eb543a7458e7fd2b5e2face3458c9f" - integrity sha512-SMICCeiNvMZnyXpuoO+ot7FHpMVPlrsR+HmfByj6nY4xYDHXLqMTbgH7ecEkDNXWkH1vaip+ZS0D7VTXwM1KYQ== + version "1.0.30001062" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001062.tgz#d814b648338504b315222ace6f1a533d9a55e390" + integrity sha512-ei9ZqeOnN7edDrb24QfJ0OZicpEbsWxv7WusOiQGz/f2SfvBgHHbOEwBJ8HKGVSyx8Z6ndPjxzR6m0NQq+0bfw== caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001043: version "1.0.30001046" @@ -7233,14 +7238,14 @@ elliptic@^6.0.0: minimalistic-crypto-utils "^1.0.0" ember-a11y-testing@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-a11y-testing/-/ember-a11y-testing-3.0.0.tgz#b2680aa115ba9eeed1d02dae8052df4053ef1435" - integrity sha512-ovkdLWINtt3sdbVgQfZ/ZiYNWB4tLaOENS6zp241gBXvo7AJqj3t9RrH1ljWAs9G8k9Cx6Z4F+dJrMJ6v/z6Hg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/ember-a11y-testing/-/ember-a11y-testing-3.0.1.tgz#011643aec55f6fbf4fa0beeca883f3e911eb0512" + integrity sha512-T+s4qsMQRftxI9wLaQhP19mqCMEa8zHMGbtZh8F0lJOkfwFcETKMXXEyrEPo/PCEiemNG00BuwOJ75teyu+fyA== dependencies: axe-core "3.5.3" - broccoli-funnel "3.0.0" + broccoli-funnel "3.0.3" ember-cli-babel "7.19.0" - ember-cli-version-checker "5.0.2" + ember-cli-version-checker "5.1.1" ember-get-config "0.2.4" ember-assign-polyfill@^2.6.0: @@ -7310,7 +7315,7 @@ ember-cli-babel-plugin-helpers@^1.0.0, ember-cli-babel-plugin-helpers@^1.1.0: resolved "https://registry.yarnpkg.com/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.1.0.tgz#de3baedd093163b6c2461f95964888c1676325ac" integrity sha512-Zr4my8Xn+CzO0gIuFNXji0eTRml5AxZUTDQz/wsNJ5AJAtyFWCY4QtKdoELNNbiCVGt1lq5yLiwTm4scGKu6xA== -ember-cli-babel@7.19.0, ember-cli-babel@^7.1.2, ember-cli-babel@^7.11.0, ember-cli-babel@^7.11.1, ember-cli-babel@^7.12.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.4.1, ember-cli-babel@^7.7.0, ember-cli-babel@^7.7.3: +ember-cli-babel@7.19.0, ember-cli-babel@^7.1.2, ember-cli-babel@^7.11.0, ember-cli-babel@^7.11.1, ember-cli-babel@^7.12.0, ember-cli-babel@^7.13.2, ember-cli-babel@^7.17.2, ember-cli-babel@^7.18.0, ember-cli-babel@^7.7.0, ember-cli-babel@^7.7.3: 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== @@ -7361,6 +7366,38 @@ ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.11.0, ember-cli-babel@^6.12.0, ember-cli-version-checker "^2.1.2" semver "^5.5.0" +ember-cli-babel@^7.10.0, ember-cli-babel@^7.19.0, ember-cli-babel@^7.4.1: + version "7.20.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.20.0.tgz#aa77eadd15036a053534fc68f7933bb97c5a1e25" + integrity sha512-DwV5Cbn8wlRFpG8zQXxYPRb0NRnnaj/2qVDODeUEjM/doDhoDDbTSSaEI5Pf0kIlkVIimyGB8qpGv1fkgj2IfQ== + dependencies: + "@babel/core" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" + "@babel/plugin-proposal-class-properties" "^7.8.3" + "@babel/plugin-proposal-decorators" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-runtime" "^7.9.0" + "@babel/plugin-transform-typescript" "^7.9.0" + "@babel/polyfill" "^7.8.7" + "@babel/preset-env" "^7.9.0" + "@babel/runtime" "^7.9.0" + amd-name-resolver "^1.2.1" + babel-plugin-debug-macros "^0.3.0" + babel-plugin-ember-data-packages-polyfill "^0.1.2" + babel-plugin-ember-modules-api-polyfill "^2.13.0" + babel-plugin-module-resolver "^3.1.1" + broccoli-babel-transpiler "^7.4.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.1" + broccoli-source "^1.1.0" + clone "^2.1.2" + ember-cli-babel-plugin-helpers "^1.1.0" + ember-cli-version-checker "^4.1.0" + ensure-posix-path "^1.0.2" + fixturify-project "^1.10.0" + rimraf "^3.0.1" + semver "^5.5.0" + ember-cli-code-coverage@^1.0.0-beta.9: version "1.0.0-beta.9" resolved "https://registry.yarnpkg.com/ember-cli-code-coverage/-/ember-cli-code-coverage-1.0.0-beta.9.tgz#4a4ca60e88fbf1895de99e3b439f46c129417ab7" @@ -7641,13 +7678,13 @@ ember-cli-uglify@^3.0.0: broccoli-uglify-sourcemap "^3.1.0" lodash.defaultsdeep "^4.6.0" -ember-cli-version-checker@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-5.0.2.tgz#7e96157be4b13b083a68078b188820193275d8c4" - integrity sha512-cqFrIg9++GKdpMv2DP8pryAhTcmCYUL2hzHatLwkcJe23s+ioZ0JQWte0avxZ5lJnwn5e3kzUKkLkDfHDFBMUw== +ember-cli-version-checker@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-5.1.1.tgz#3185c526c14671609cbd22ab0d0925787fc84f3d" + integrity sha512-YziSW1MgOuVdJSyUY2CKSC4vXrGQIHF6FgygHkJOxYGjZNQYwf5MK0sbliKatvJf7kzDSnXs+r8JLrD74W/A8A== dependencies: resolve-package-path "^2.0.0" - semver "^7.1.3" + semver "^7.3.2" silent-error "^1.1.1" ember-cli-version-checker@^1.0.2: @@ -7960,6 +7997,26 @@ ember-maybe-import-regenerator@^0.1.6: ember-cli-babel "^6.0.0-beta.4" regenerator-runtime "^0.9.5" +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== + dependencies: + ember-cli-babel "^7.10.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-page-title@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/ember-page-title/-/ember-page-title-5.2.1.tgz#12261e010bec96af6200cd132fe4068e717ccbec" @@ -8008,6 +8065,11 @@ ember-rfc176-data@^0.3.12: resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.12.tgz#90d82878e69e2ac9a5438e8ce14d12c6031c5bd2" integrity sha512-g9HeZj/gU5bfIIrGXkP7MhS2b3Vu5DfNUrYr14hy99TgIvtZETO+96QF4WOEUXGjIJdfTRjerVnQlqngPQSv1g== +ember-rfc176-data@^0.3.13: + version "0.3.13" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.13.tgz#ed1712a26e65fec703655f35410414aa1982cf3b" + integrity sha512-m9JbwQlT6PjY7x/T8HslnXP7Sz9bx/pz3FrNfNi2NesJnbNISly0Lix6NV1fhfo46572cpq4jrM+/6yYlMefTQ== + ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee"