refactor: 💡 replace layout regions with anonymous component

This commit is contained in:
Randall Morey committed 2020-06-10 14:21:26 -04:00
1 parent 45af417372
commit 2c295afdfd
47 files changed
+108 -362

No files matched your search

@@ -0,0 +1,10 @@
import Component from '@ember/component';
import layout from '../../templates/components/rose/anonymous';
/**
* An otherwise empty component that renders a block. Used only by components
* that yield simple contextual components, such as layouts yielding regions.
*/
export default Component.extend({
layout
});
@@ -0,0 +1,25 @@
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
import { hbs } from 'ember-cli-htmlbars';
import { action } from '@storybook/addon-actions';
import { text, boolean, select } from '@storybook/addon-knobs';
<Meta title="Rose|Anonymous" component="Anonymous" />
# Anonymous
The anonymous component is a simple `<div>` with no attributes of its own.
It is used by other components that need to yield contextual components.
This component should not be instantiated directly.
For example, layout components may yield an anonymous component to configure
various layout regions:
```htmlbars
<div ...attributes class="rose-layout-global">
{{yield (hash
header=(component "rose/anonymous" tagName="header" class="rose-layout-global-header")
sidebar=(component "rose/anonymous" tagName="aside" class="rose-layout-global-sidebar")
body=(component "rose/anonymous" tagName="main" class="rose-layout-global-body")
)}}
</div>
```
@@ -10,20 +10,20 @@ import { text, boolean, select } from '@storybook/addon-knobs';
A top-level layout/positioning component that allows three distinct sections to be configured: header, navigation, and body.
```htmlbars
<Rose::Layout::Global as |global|>
<global.header />
<global.body />
<global.navigation />
<Rose::Layout::Global as |layout|>
<layout.header />
<layout.sidebar />
<layout.body />
</Rose::Layout::Global>
```
<Preview>
<Story name="Global">{{
template: hbs`
<Rose::Layout::Global as |global|>
<global.header style="background: var(--brand-gray-5);">Header</global.header>
<global.body style="background: var(--brand-gray-7);">Body</global.body>
<global.navigation style="background: var(--brand-gray-6);">Navigation</global.navigation>
<Rose::Layout::Global as |layout|>
<layout.header style="background: var(--brand-gray-5);">Header</layout.header>
<layout.sidebar style="background: var(--brand-gray-6);">Sidebar</layout.sidebar>
<layout.body style="background: var(--brand-gray-7);">Body</layout.body>
</Rose::Layout::Global>
`,
}}</Story>
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/global/body';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/global/header';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/global/navigation';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/page/actions';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/page/body';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/page/breadcrumbs';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/page/header';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,7 +0,0 @@
import Component from '@ember/component';
import layout from '../../../../templates/components/rose/layout/page/navigation';
export default Component.extend({
layout,
tagName: '',
});
@@ -1,9 +1,5 @@
@use '../../../variables/sizing';
@use '../../../variables/media';
@import 'header';
@import 'body';
@import 'navigation';
@use '../../variables/sizing';
@use '../../variables/media';
.rose-layout-global {
display: grid;
@@ -14,6 +10,20 @@
grid-template-columns: (sizing.rems(m) * 16) auto 1fr;
grid-template-rows: auto 1fr;
height: 100vh;
.rose-layout-global-body {
grid-area: body;
}
.rose-layout-global-header {
grid-area: header;
}
.rose-layout-global-sidebar {
grid-area: navigation;
border-right: sizing.rems(xxxxs) solid var(--ui-border-subtler-1);
}
}
@media (max-width: media.width(small)) {
@@ -1,3 +0,0 @@
.rose-layout-global-body {
grid-area: body;
}
@@ -1,3 +0,0 @@
.rose-layout-global-header {
grid-area: header;
}
@@ -1,6 +0,0 @@
@use '../../../variables/sizing';
.rose-layout-global-navigation {
grid-area: navigation;
border-right: sizing.rems(xxxxs) solid var(--ui-border-subtler-1);
}
@@ -0,0 +1 @@
{{yield}}
@@ -1,7 +1,7 @@
<div ...attributes class="rose-layout-global">
{{yield (hash
header=(component 'rose/layout/global/header')
body=(component 'rose/layout/global/body')
navigation=(component 'rose/layout/global/navigation')
header=(component "rose/anonymous" tagName="header" class="rose-layout-global-header")
sidebar=(component "rose/anonymous" tagName="aside" class="rose-layout-global-sidebar")
body=(component "rose/anonymous" tagName="main" class="rose-layout-global-body")
)}}
</div>
@@ -1,3 +0,0 @@
<main ...attributes class="rose-layout-global-body">
{{yield}}
</main>
@@ -1,3 +0,0 @@
<header ...attributes class="rose-layout-global-header" >
{{yield}}
</header>
@@ -1,3 +0,0 @@
<aside ...attributes class="rose-layout-global-navigation">
{{yield}}
</aside>
@@ -1,9 +1,9 @@
<div ...attributes class="rose-layout-page">
{{yield (hash
breadcrumbs=(component 'rose/layout/page/breadcrumbs')
header=(component 'rose/layout/page/header')
actions=(component 'rose/layout/page/actions')
navigation=(component 'rose/layout/page/navigation')
body=(component 'rose/layout/page/body')
breadcrumbs=(component "rose/anonymous" class="rose-layout-page-breadcrumbs")
header=(component "rose/anonymous" class="rose-layout-page-header")
actions=(component "rose/anonymous" class="rose-layout-page-actions")
navigation=(component "rose/anonymous" class="rose-layout-page-navigation")
body=(component "rose/anonymous" class="rose-layout-page-body")
)}}
</div>
@@ -1,3 +0,0 @@
<div ...attributes class="rose-layout-page-actions">
{{yield}}
</div>
@@ -1,3 +0,0 @@
<div ...attributes class="rose-layout-page-body">
{{yield}}
</div>
@@ -1,3 +0,0 @@
<div ...attributes class="rose-layout-page-breadcrumbs">
{{yield}}
</div>
@@ -1,3 +0,0 @@
<div ...attributes class="rose-layout-page-header">
{{yield}}
</div>
@@ -1,3 +0,0 @@
<div ...attributes class="rose-layout-page-navigation">
{{yield}}
</div>
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/anonymous';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/global/body';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/global/header';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/global/navigation';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/page/actions';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/page/body';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/page/breadcrumbs';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/page/header';
@@ -1 +0,0 @@
export { default } from 'rose/components/rose/layout/page/navigation';
@@ -1,5 +1,5 @@
<Rose::Layout::Global as |global|>
<global.header>
<Rose::Layout::Global as |layout|>
<layout.header>
<Rose::Header as |header|>
<header.brand @logo="logo" @text="Product Name" />
@@ -28,18 +28,18 @@
</header.utilities>
</Rose::Header>
</global.header>
</layout.header>
<global.navigation>
<layout.sidebar>
<Rose::Nav::Sidebar @title="Title" as |nav|>
<nav.link @route="index">Item Name</nav.link>
<nav.link @route="about">Item Name</nav.link>
<nav.link @route="about">Item Name</nav.link>
<nav.link @route="about">Item Name</nav.link>
</Rose::Nav::Sidebar>
</global.navigation>
</layout.sidebar>
<global.body>
<layout.body>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>Breadcrumbs</page.breadcrumbs>
<page.header>Header</page.header>
@@ -229,5 +229,5 @@
</footer.row>
</table.footer>
</Rose::Table>
</global.body>
</layout.body>
</Rose::Layout::Global>
@@ -0,0 +1,18 @@
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/anonymous', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
await render(hbs`
{{#rose/anonymous tagName='main'}}
template block text
{{/rose/anonymous}}
`);
assert.ok(find('main'));
assert.equal(this.element.textContent.trim(), 'template block text');
});
});
@@ -18,30 +18,30 @@ module('Integration | Component | rose/layout/global', function (hooks) {
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Global as |global|>
await render(hbs`<Rose::Layout::Global as |layout|>
<button id="content" />
</Rose::Layout::Global>`);
assert.ok(find('#content'));
});
test('it renders with header', async function (assert) {
await render(hbs`<Rose::Layout::Global as |global|>
<global.header />
await render(hbs`<Rose::Layout::Global as |layout|>
<layout.header />
</Rose::Layout::Global>`);
assert.ok(find('.rose-layout-global-header'));
});
test('it renders with main', async function (assert) {
await render(hbs`<Rose::Layout::Global as |global|>
<global.body />
await render(hbs`<Rose::Layout::Global as |layout|>
<layout.body />
</Rose::Layout::Global>`);
assert.ok(find('.rose-layout-global-body'));
});
test('it renders with sidebar', async function (assert) {
await render(hbs`<Rose::Layout::Global as |global|>
<global.navigation />
await render(hbs`<Rose::Layout::Global as |layout|>
<layout.sidebar />
</Rose::Layout::Global>`);
assert.ok(find('.rose-layout-global-navigation'));
assert.ok(find('.rose-layout-global-sidebar'));
});
});
@@ -1,26 +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/layout/global/body', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Global::Body />`);
assert.ok(find('main'));
assert.ok(find('.rose-layout-global-body'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Global::Body id="main"/>`);
assert.ok(find('#main'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Global::Body>
<button id="content" />
</Rose::Layout::Global::Body>`);
assert.ok(find('#content'));
});
});
@@ -1,26 +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/layout/global/header', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Global::Header />`);
assert.ok(find('header'));
assert.ok(find('.rose-layout-global-header'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Global::Header id="header"/>`);
assert.ok(find('#header'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Global::Header>
<button id="content" />
</Rose::Layout::Global::Header>`);
assert.ok(find('#content'));
});
});
@@ -1,28 +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/layout/global/navigation', function (
hooks
) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Global::Navigation />`);
assert.ok(find('aside'));
assert.ok(find('.rose-layout-global-navigation'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Global::Navigation id="navigation"/>`);
assert.ok(find('#navigation'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Global::Navigation>
<button id="content" />
</Rose::Layout::Global::Navigation>`);
assert.ok(find('#content'));
});
});
@@ -1,26 +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/layout/page/actions', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Page::Actions />`);
assert.ok(find('div'));
assert.ok(find('.rose-layout-page-actions'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Page::Actions id="actions"/>`);
assert.ok(find('#actions'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Page::Actions>
<button id="content" />
</Rose::Layout::Page::Actions>`);
assert.ok(find('#content'));
});
});
@@ -1,26 +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/layout/page/body', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Page::Body />`);
assert.ok(find('div'));
assert.ok(find('.rose-layout-page-body'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Page::Body id="body"/>`);
assert.ok(find('#body'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Page::Body>
<button id="content" />
</Rose::Layout::Page::Body>`);
assert.ok(find('#content'));
});
});
@@ -1,28 +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/layout/page/breadcrumbs', function (
hooks
) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Page::Breadcrumbs />`);
assert.ok(find('div'));
assert.ok(find('.rose-layout-page-breadcrumbs'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Page::Breadcrumbs id="breadcrumbs"/>`);
assert.ok(find('#breadcrumbs'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Page::Breadcrumbs>
<button id="content" />
</Rose::Layout::Page::Breadcrumbs>`);
assert.ok(find('#content'));
});
});
@@ -1,26 +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/layout/page/header', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Page::Header />`);
assert.ok(find('div'));
assert.ok(find('.rose-layout-page-header'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Page::Header id="header"/>`);
assert.ok(find('#header'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Page::Header>
<button id="content" />
</Rose::Layout::Page::Header>`);
assert.ok(find('#content'));
});
});
@@ -1,28 +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/layout/page/navigation', function (
hooks
) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Layout::Page::Navigation />`);
assert.ok(find('div'));
assert.ok(find('.rose-layout-page-navigation'));
});
test('it renders with attributes', async function (assert) {
await render(hbs`<Rose::Layout::Page::Navigation id="navigation"/>`);
assert.ok(find('#navigation'));
});
test('it renders with content', async function (assert) {
await render(hbs`<Rose::Layout::Page::Navigation>
<button id="content" />
</Rose::Layout::Page::Navigation>`);
assert.ok(find('#content'));
});
});
+6 -11
View File
@@ -1,5 +1,6 @@
<Rose::Layout::Global as |global|>
<global.header>
<Rose::Layout::Global as |layout|>
<layout.header>
<Rose::Header as |header|>
<header.brand @logo="logo-hashi" @text={{app-name}} />
<header.nav as |nav|>
@@ -22,17 +23,11 @@
</utilities.dropdown>
</header.utilities>
</Rose::Header>
</global.header>
</layout.header>
<global.body>
{{outlet}}
</global.body>
<layout.sidebar>{{outlet "sidebar"}}</layout.sidebar>
<global.navigation>
{{outlet "sidebar"}}
</global.navigation>
<layout.body>{{outlet}}</layout.body>
</Rose::Layout::Global>