diff --git a/addons/rose/addon/components/rose/header.stories.mdx b/addons/rose/addon/components/rose/header.stories.mdx index 5f69caffa..d546e5c5e 100644 --- a/addons/rose/addon/components/rose/header.stories.mdx +++ b/addons/rose/addon/components/rose/header.stories.mdx @@ -14,13 +14,12 @@ A header component that allows three distinct sections to be configured: brand, - - Org name - - link - button - + + Menu item + Menu item + Button menu item + Section Section @@ -42,14 +41,13 @@ A header component that allows three distinct sections to be configured: brand, - - {{nav-dropdown-label}} - - {{nav-dropdown-link-label}} - {{nav-dropdown-button-label}} - + + Menu item + Menu item + Button menu item - {{nav-link-label}} + Section + Section @@ -63,7 +61,7 @@ A header component that allows three distinct sections to be configured: brand, `, context: { - 'nav-dropdown-label': text('nav-dropdown-label', 'Org Name'), + 'nav-dropdown-label': text('nav-dropdown-label', 'org-name'), 'nav-dropdown-link-label': text('nav-dropdown-link-label', 'Menu Item'), 'nav-dropdown-button-label': text('nav-dropdown-button-label', 'Menu Item'), 'nav-link-label': text('nav-link-label', 'Section'), diff --git a/addons/rose/addon/components/rose/header/dropdown/content.js b/addons/rose/addon/components/rose/header/dropdown/content.js deleted file mode 100644 index 4f2bf32a0..000000000 --- a/addons/rose/addon/components/rose/header/dropdown/content.js +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index fa19bd4b9..000000000 --- a/addons/rose/addon/components/rose/header/dropdown/content/button.js +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 72ffb581c..000000000 --- a/addons/rose/addon/components/rose/header/dropdown/trigger.js +++ /dev/null @@ -1,7 +0,0 @@ -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/modifiers/on-click-outside.js b/addons/rose/addon/modifiers/on-click-outside.js index 8feb0335e..be434a234 100644 --- a/addons/rose/addon/modifiers/on-click-outside.js +++ b/addons/rose/addon/modifiers/on-click-outside.js @@ -1,5 +1,10 @@ import { modifier } from 'ember-modifier'; +/** + * Used to detect clicks occuring _outside_ of the modified element. + * This is useful especially for dropdowns to toggle content visibility + * when the user clicks away. + */ export default modifier((element, [callback]) => { function handleClick(event) { if (!element.contains(event.target)) { diff --git a/addons/rose/addon/styles/rose/components/header/_catchall.scss b/addons/rose/addon/styles/rose/components/header/_catchall.scss index f7355deb2..0d01e8090 100644 --- a/addons/rose/addon/styles/rose/components/header/_catchall.scss +++ b/addons/rose/addon/styles/rose/components/header/_catchall.scss @@ -12,37 +12,6 @@ .rose-header-nav, .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; @@ -56,27 +25,6 @@ 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; - } - } } } } diff --git a/addons/rose/addon/styles/rose/components/header/_dropdown.scss b/addons/rose/addon/styles/rose/components/header/_dropdown.scss new file mode 100644 index 000000000..3584c3126 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/header/_dropdown.scss @@ -0,0 +1,76 @@ +@use 'sass:map'; +@use '../../variables/sizing'; +@use '../../utilities/type'; + +$dropdown-chevron: ( + 'default': + "data:image/svg+xml;utf-8,", +); + +.rose-header-dropdown { + position: relative; + + .rose-header-dropdown-trigger { + cursor: default; + color: var(--white); + background: url(map.get($dropdown-chevron, default)) no-repeat right center; + margin-right: sizing.rems(s); + padding-right: sizing.rems(l); + + // Hide default twistie triangle + // Webkit / Chromium + &::-webkit-details-marker { + display: none; + } + // Firefox + list-style-type: none; + &::marker { + display: none; + } + } + + .rose-header-dropdown-content { + $xs: sizing.rems(xs); // 8 + $xxs: sizing.rems(xxs); // 4 + position: absolute; + padding: $xxs 0; + border: 1px solid var(--ui-gray-subtler-2); + border-radius: sizing.rems(xxxs); + background: var(--subtle); + box-shadow: 0 $xxs $xxs rgba(var(--stark-components), var(--opacity-3)), + 0 $xxs $xs rgba(var(--stark-components), var(--opacity-4)); + } + + &.dropdown-right { + .rose-header-dropdown-content { + right: 0; + } + } + + .rose-header-dropdown-link, + .rose-button-header-dropdown { + @include type.type(m, normal); + display: block; + // Targeting min-width of 200 + min-width: (sizing.rems(m) + sizing.rems(xxs)) * 10; + padding: 0 sizing.rems(s); + margin: 0; + border: 0; + color: var(--stark); + background-color: transparent; + // target line height is 36, which is not a standard line height for this + // font size + $lineHeight: 36 / 16; + line-height: $lineHeight; + text-align: left; + text-decoration: none; + + &:hover { + background-color: var(--ui-gray-subtler-4); + } + } + + .rose-button-header-dropdown { + width: 100%; + } +} diff --git a/addons/rose/addon/styles/rose/components/header/_index.scss b/addons/rose/addon/styles/rose/components/header/_index.scss index 25dc59f2f..fd0595fe6 100644 --- a/addons/rose/addon/styles/rose/components/header/_index.scss +++ b/addons/rose/addon/styles/rose/components/header/_index.scss @@ -5,13 +5,7 @@ @import 'brand'; @import 'nav'; @import 'link'; - -$dropdown-chevron: ( - 'default': - "data:image/svg+xml;utf-8,", - 'open': - "data:image/svg+xml;utf-8,", -); +@import 'dropdown'; .rose-header { display: grid; diff --git a/addons/rose/addon/templates/components/rose/header/dropdown.hbs b/addons/rose/addon/templates/components/rose/header/dropdown.hbs index 3f4810eea..f9376ddfe 100644 --- a/addons/rose/addon/templates/components/rose/header/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/header/dropdown.hbs @@ -1,8 +1,18 @@ -
+
+ + + {{@text}} + + +
+ {{yield (hash + link=(component "link-to" class="rose-header-dropdown-link") + button=(component "rose/button" style="header-dropdown") + )}} +
- {{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 deleted file mode 100644 index 68af8036a..000000000 --- a/addons/rose/addon/templates/components/rose/header/dropdown/content.hbs +++ /dev/null @@ -1,6 +0,0 @@ - - {{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 deleted file mode 100644 index e437e4689..000000000 --- a/addons/rose/addon/templates/components/rose/header/dropdown/content/button.hbs +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/addons/rose/addon/templates/components/rose/header/dropdown/trigger.hbs b/addons/rose/addon/templates/components/rose/header/dropdown/trigger.hbs deleted file mode 100644 index f513aa8bd..000000000 --- a/addons/rose/addon/templates/components/rose/header/dropdown/trigger.hbs +++ /dev/null @@ -1,4 +0,0 @@ - - {{yield}} - - diff --git a/addons/rose/app/components/rose/header/dropdown/content.js b/addons/rose/app/components/rose/header/dropdown/content.js deleted file mode 100644 index 51792f92e..000000000 --- a/addons/rose/app/components/rose/header/dropdown/content.js +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index cc70f39b5..000000000 --- a/addons/rose/app/components/rose/header/dropdown/content/button.js +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 0bb1491ed..000000000 --- a/addons/rose/app/components/rose/header/dropdown/trigger.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'rose/components/rose/header/dropdown/trigger'; diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index 4425c58a8..aaa68d9be 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -3,22 +3,16 @@ + + Menu item + Menu item + Button menu item + Section Section {{!-- - - - Org name - - link - button - - - Section - - diff --git a/addons/rose/tests/integration/components/rose/header/dropdown-test.js b/addons/rose/tests/integration/components/rose/header/dropdown-test.js index 439c29800..fcb355cf1 100644 --- a/addons/rose/tests/integration/components/rose/header/dropdown-test.js +++ b/addons/rose/tests/integration/components/rose/header/dropdown-test.js @@ -20,10 +20,7 @@ module('Integration | Component | rose/header/dropdown', function (hooks) { }); test('it renders with trigger', async function (assert) { - await render(hbs` - Click me - `); - assert.ok(find('.rose-header-dropdown-trigger')); + await render(hbs``); assert.equal( find('.rose-header-dropdown-trigger').textContent.trim(), 'Click me' @@ -31,14 +28,12 @@ module('Integration | Component | rose/header/dropdown', function (hooks) { }); test('it renders with content', async function (assert) { - await render(hbs` - - - - - - - + await render(hbs` + + + + + `); assert.ok(find('.rose-header-dropdown-content')); assert.equal(findAll('a').length, 2); @@ -46,32 +41,24 @@ module('Integration | Component | rose/header/dropdown', function (hooks) { }); test('it is toggled on click on trigger content', async function (assert) { - await render(hbs` - Click me - - - - `); + await render(hbs``); + assert.notOk(find('#dropdown').open); - - await click('#trigger'); + await click('summary'); assert.ok(find('#dropdown').open); - - await click('#trigger'); + await click('summary'); assert.notOk(find('#dropdown').open); }); test('it is closed with outside click is triggered', async function (assert) { - await render(hbs`
- Click me - - - -
`); + await render(hbs` +
+ +
+ `); - await click('#trigger'); + await click('summary'); 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 deleted file mode 100644 index b0bb4a371..000000000 --- a/addons/rose/tests/integration/components/rose/header/dropdown/content-test.js +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index a73dc28df..000000000 --- a/addons/rose/tests/integration/components/rose/header/dropdown/content/button-test.js +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index 83309f23e..000000000 --- a/addons/rose/tests/integration/components/rose/header/dropdown/trigger-test.js +++ /dev/null @@ -1,41 +0,0 @@ -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')); - }); -});