From 13f76659e4136bae915f9fb1afd4a868bfae42e1 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Fri, 7 Aug 2020 14:35:00 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20key/value=20list?= =?UTF-8?q?=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../addon/components/rose/list/key-value.js | 7 ++ .../rose/list/key-value.stories.mdx | 103 ++++++++++++++++++ .../components/rose/list/key-value/item.js | 8 ++ .../addon/styles/rose/components/_index.scss | 1 + .../styles/rose/components/form/_input.scss | 1 + .../styles/rose/components/form/_select.scss | 1 + .../styles/rose/components/list/_index.scss | 1 + .../rose/components/list/_key-value.scss | 45 ++++++++ .../components/rose/list/key-value.hbs | 5 + .../components/rose/list/key-value/item.hbs | 13 +++ .../app/components/rose/list/key-value.js | 1 + .../components/rose/list/key-value/item.js | 1 + .../rose/tests/dummy/app/templates/index.hbs | 27 +---- .../tests/dummy/app/templates/playground.hbs | 48 +++++++- .../components/rose/list/key-value-test.js | 30 +++++ 15 files changed, 269 insertions(+), 23 deletions(-) create mode 100644 addons/rose/addon/components/rose/list/key-value.js create mode 100644 addons/rose/addon/components/rose/list/key-value.stories.mdx create mode 100644 addons/rose/addon/components/rose/list/key-value/item.js create mode 100644 addons/rose/addon/styles/rose/components/list/_index.scss create mode 100644 addons/rose/addon/styles/rose/components/list/_key-value.scss create mode 100644 addons/rose/addon/templates/components/rose/list/key-value.hbs create mode 100644 addons/rose/addon/templates/components/rose/list/key-value/item.hbs create mode 100644 addons/rose/app/components/rose/list/key-value.js create mode 100644 addons/rose/app/components/rose/list/key-value/item.js create mode 100644 addons/rose/tests/integration/components/rose/list/key-value-test.js diff --git a/addons/rose/addon/components/rose/list/key-value.js b/addons/rose/addon/components/rose/list/key-value.js new file mode 100644 index 000000000..0d173250c --- /dev/null +++ b/addons/rose/addon/components/rose/list/key-value.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/list/key-value'; + +export default Component.extend({ + layout, + tagName: '' +}); diff --git a/addons/rose/addon/components/rose/list/key-value.stories.mdx b/addons/rose/addon/components/rose/list/key-value.stories.mdx new file mode 100644 index 000000000..b37e554ff --- /dev/null +++ b/addons/rose/addon/components/rose/list/key-value.stories.mdx @@ -0,0 +1,103 @@ +import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; +import { hbs } from 'ember-cli-htmlbars'; +import { action } from '@storybook/addon-actions'; + + + +# Key/Value List + +A simple key/value list with support for embedded form fields and buttons. + + + {{ + template: hbs` + + + Key + Value + + + Key + Value + + + Key + Value + + + + + Key + + + + + + Add + + + + + + + Key + + + + + + Remove + + + + + `, + }} + + +```html + + + Key + Value + + + Key + Value + + + Key + Value + + + {{!-- In actual use, form fields should be yielded from an outer form component --}} + + + + Key + + + + + + Add + + + + + + + + Key + + + + + + Remove + + + + + +``` diff --git a/addons/rose/addon/components/rose/list/key-value/item.js b/addons/rose/addon/components/rose/list/key-value/item.js new file mode 100644 index 000000000..291e1b9da --- /dev/null +++ b/addons/rose/addon/components/rose/list/key-value/item.js @@ -0,0 +1,8 @@ +import Component from '@ember/component'; +import layout from '../../../../templates/components/rose/list/key-value/item'; +import ComponentAutoId from '../../../../mixins/component-auto-id'; + +export default Component.extend(ComponentAutoId, { + layout, + tagName: '' +}); diff --git a/addons/rose/addon/styles/rose/components/_index.scss b/addons/rose/addon/styles/rose/components/_index.scss index dd35e9d22..19a9d3de6 100644 --- a/addons/rose/addon/styles/rose/components/_index.scss +++ b/addons/rose/addon/styles/rose/components/_index.scss @@ -4,6 +4,7 @@ @import 'header'; @import 'layout'; @import 'icon'; +@import 'list'; @import 'notification'; @import 'card'; @import 'cards'; diff --git a/addons/rose/addon/styles/rose/components/form/_input.scss b/addons/rose/addon/styles/rose/components/form/_input.scss index e5be517eb..4b898f4ef 100644 --- a/addons/rose/addon/styles/rose/components/form/_input.scss +++ b/addons/rose/addon/styles/rose/components/form/_input.scss @@ -9,6 +9,7 @@ @include type.type(m); display: inline-block; box-sizing: border-box; + width: 100%; margin-bottom: sizing.rems(xs); padding: sizing.rems(xs); color: var(--stark); diff --git a/addons/rose/addon/styles/rose/components/form/_select.scss b/addons/rose/addon/styles/rose/components/form/_select.scss index d5d4a499a..4e1902da0 100644 --- a/addons/rose/addon/styles/rose/components/form/_select.scss +++ b/addons/rose/addon/styles/rose/components/form/_select.scss @@ -13,6 +13,7 @@ vertical-align: middle; display: inline-block; box-sizing: border-box; + width: 100%; margin-bottom: sizing.rems(xs); padding: sizing.rems(xs) sizing.rems(xxl) sizing.rems(xs) sizing.rems(xs); border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-2); diff --git a/addons/rose/addon/styles/rose/components/list/_index.scss b/addons/rose/addon/styles/rose/components/list/_index.scss new file mode 100644 index 000000000..f52188987 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/list/_index.scss @@ -0,0 +1 @@ +@import 'key-value'; diff --git a/addons/rose/addon/styles/rose/components/list/_key-value.scss b/addons/rose/addon/styles/rose/components/list/_key-value.scss new file mode 100644 index 000000000..a6b54eb24 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/list/_key-value.scss @@ -0,0 +1,45 @@ +@use '../../variables/sizing'; +@use '../../variables/typography'; +@use '../../utilities/type'; + +.rose-list-key-value-item { + display: flex; + border-bottom: 1px solid var(--ui-gray-subtler-3); + @include type.type(s); + $lineHeight: 36 / 14; + line-height: $lineHeight; + padding: (sizing.rems(s) / 2) 0; + + .rose-list-key-value-item-cell { + display: flex; + align-items: center; + margin-right: sizing.rems(m); + + // Eliminate top/bottom margin from children + > * { + margin-bottom: 0; + margin-top: 0; + } + + &:last-child { + &, + & > * { + margin-right: 0; + } + } + + // First cell (key) is approximately 25% + &:nth-child(1) { + width: 25%; + font-weight: typography.font-weight(semibold); + } + + // Second cell (value) is approximately 75% + &:nth-child(2) { + flex-grow: 1; + } + + // Remaining cells will take up as little space as necessary to + // suit their content. + } +} diff --git a/addons/rose/addon/templates/components/rose/list/key-value.hbs b/addons/rose/addon/templates/components/rose/list/key-value.hbs new file mode 100644 index 000000000..2cd7a3d44 --- /dev/null +++ b/addons/rose/addon/templates/components/rose/list/key-value.hbs @@ -0,0 +1,5 @@ + diff --git a/addons/rose/addon/templates/components/rose/list/key-value/item.hbs b/addons/rose/addon/templates/components/rose/list/key-value/item.hbs new file mode 100644 index 000000000..a4585afaa --- /dev/null +++ b/addons/rose/addon/templates/components/rose/list/key-value/item.hbs @@ -0,0 +1,13 @@ +
  • + {{yield (hash + key=(component 'rose/anonymous' + id=(concat "item-key-" this.id) + tagName='div' + classNames='rose-list-key-value-item-cell' + ) + cell=(component 'rose/anonymous' + tagName='div' + classNames='rose-list-key-value-item-cell' + ) + )}} +
  • diff --git a/addons/rose/app/components/rose/list/key-value.js b/addons/rose/app/components/rose/list/key-value.js new file mode 100644 index 000000000..c2016a1d1 --- /dev/null +++ b/addons/rose/app/components/rose/list/key-value.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/list/key-value'; \ No newline at end of file diff --git a/addons/rose/app/components/rose/list/key-value/item.js b/addons/rose/app/components/rose/list/key-value/item.js new file mode 100644 index 000000000..842352028 --- /dev/null +++ b/addons/rose/app/components/rose/list/key-value/item.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/list/key-value/item'; \ No newline at end of file diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index 95220225a..2974ba49c 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -1,21 +1,6 @@ -Default -Default Outline -Default with Icon - -Light -Dark - -Informational -Informational Outline - -Alert -Alert Outline - -Error -Error Outline - -Success -Success Outline - -Warning -Warning Outline + + + Key + Value + + diff --git a/addons/rose/tests/dummy/app/templates/playground.hbs b/addons/rose/tests/dummy/app/templates/playground.hbs index cf74a1e48..e9ace3c02 100644 --- a/addons/rose/tests/dummy/app/templates/playground.hbs +++ b/addons/rose/tests/dummy/app/templates/playground.hbs @@ -33,7 +33,7 @@ - + Item Name @@ -44,7 +44,51 @@ - Body content + + + + Key + Value + + + Key + Value + + + Key + Value + + + + + + Key + + + + + + Add + + + + + + + + Key + + + + + + Remove + + + + + + diff --git a/addons/rose/tests/integration/components/rose/list/key-value-test.js b/addons/rose/tests/integration/components/rose/list/key-value-test.js new file mode 100644 index 000000000..086bf9b64 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/list/key-value-test.js @@ -0,0 +1,30 @@ +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/list/key-value', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + assert.expect(2); + await render(hbs` + + + Key + Value + + + Key + Value + + + `); + const itemLabelledBy = find('.rose-list-key-value-item:first-child').getAttribute('aria-labelledby'); + assert.equal(findAll('.rose-list-key-value-item').length, 2, 'it has two items'); + assert.ok( + find(`.rose-list-key-value-item:first-child > .rose-list-key-value-item-cell:first-child#${itemLabelledBy}`), + 'The key cell has an ID associated with the `aria-labelledby` attribute of its parent item element' + ); + }); +});