From ce4135ea79f876aedf271a634c8379b167678b1d Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 27 May 2020 11:15:31 -0400 Subject: [PATCH 01/10] =?UTF-8?q?chore:=20=F0=9F=A4=96=20add=20form=20acti?= =?UTF-8?q?ons=20component=20and=20tweak=20form=20spacing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../addon/components/rose/form/actions.js | 24 ++++++++++ .../components/rose/form/actions.stories.mdx | 42 +++++++++++++++++ .../styles/rose/components/form/_actions.scss | 3 ++ .../styles/rose/components/form/_index.scss | 1 + .../styles/rose/components/form/_input.scss | 2 +- .../styles/rose/components/form/_select.scss | 2 +- .../addon/styles/rose/utilities/_button.scss | 47 +++++++++++-------- .../templates/components/rose/button.hbs | 47 ++++++++++--------- .../components/rose/form/actions.hbs | 19 ++++++++ .../rose/app/components/rose/form/actions.js | 1 + .../rose/tests/dummy/app/controllers/index.js | 2 +- .../rose/tests/dummy/app/templates/index.hbs | 10 +++- .../components/rose/form/actions-test.js | 38 +++++++++++++++ 13 files changed, 190 insertions(+), 48 deletions(-) create mode 100644 addons/rose/addon/components/rose/form/actions.js create mode 100644 addons/rose/addon/components/rose/form/actions.stories.mdx create mode 100644 addons/rose/addon/styles/rose/components/form/_actions.scss create mode 100644 addons/rose/addon/templates/components/rose/form/actions.hbs create mode 100644 addons/rose/app/components/rose/form/actions.js create mode 100644 addons/rose/tests/integration/components/rose/form/actions-test.js diff --git a/addons/rose/addon/components/rose/form/actions.js b/addons/rose/addon/components/rose/form/actions.js new file mode 100644 index 000000000..4bfcbea85 --- /dev/null +++ b/addons/rose/addon/components/rose/form/actions.js @@ -0,0 +1,24 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/form/actions'; + +/** + * A set of two form action buttons for submit and cancel. + * To handle submit, place a submit handler on the parent form element. + * To handle cancel button click, pass in a function to `@cancel`. + * + * @example + * + */ +export default Component.extend({ + layout, + tagName: '', + + /** + * @type {boolean} + */ + showCancel: true, +}); diff --git a/addons/rose/addon/components/rose/form/actions.stories.mdx b/addons/rose/addon/components/rose/form/actions.stories.mdx new file mode 100644 index 000000000..7517bddb6 --- /dev/null +++ b/addons/rose/addon/components/rose/form/actions.stories.mdx @@ -0,0 +1,42 @@ +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'; + + + +# Form Actions + +A simple collection of buttons for performing common actions like submit/save +and cancel. Form actions should always be used in the context of a form element +where the form has a submit action handler. The submit button does not directly +support actions. The cancel button supports a cancel action. + +```html + +``` + + + {{ + template: hbs` + + `, + context: { + submitText: text('submitText', 'Save'), + cancelText: text('cancelText', 'Cancel'), + showCancel: boolean('showCancel', true), + disabled: boolean('disabled', false), + onCancel: action('cancel'), + }, + }} + diff --git a/addons/rose/addon/styles/rose/components/form/_actions.scss b/addons/rose/addon/styles/rose/components/form/_actions.scss new file mode 100644 index 000000000..4c2d62a0a --- /dev/null +++ b/addons/rose/addon/styles/rose/components/form/_actions.scss @@ -0,0 +1,3 @@ +.rose-form-actions { + //display: flex; +} diff --git a/addons/rose/addon/styles/rose/components/form/_index.scss b/addons/rose/addon/styles/rose/components/form/_index.scss index c8c516f8c..29fa5e995 100644 --- a/addons/rose/addon/styles/rose/components/form/_index.scss +++ b/addons/rose/addon/styles/rose/components/form/_index.scss @@ -2,3 +2,4 @@ @import 'checkbox'; @import 'select'; @import 'radio'; +@import 'actions'; diff --git a/addons/rose/addon/styles/rose/components/form/_input.scss b/addons/rose/addon/styles/rose/components/form/_input.scss index 7116c6a76..0895f7f17 100644 --- a/addons/rose/addon/styles/rose/components/form/_input.scss +++ b/addons/rose/addon/styles/rose/components/form/_input.scss @@ -2,7 +2,7 @@ @use '../../utilities/type'; .rose-form-input { - margin-bottom: sizing.rems(m); + margin-bottom: sizing.rems(l); .rose-form-input-label { @include type.type(s, semibold); diff --git a/addons/rose/addon/styles/rose/components/form/_select.scss b/addons/rose/addon/styles/rose/components/form/_select.scss index 63cb16911..9effb0b80 100644 --- a/addons/rose/addon/styles/rose/components/form/_select.scss +++ b/addons/rose/addon/styles/rose/components/form/_select.scss @@ -2,7 +2,7 @@ @use '../../utilities/type'; .rose-form-select { - margin-bottom: sizing.rems(m); + margin-bottom: sizing.rems(l); .rose-form-select-label { @include type.type(s, semibold); diff --git a/addons/rose/addon/styles/rose/utilities/_button.scss b/addons/rose/addon/styles/rose/utilities/_button.scss index 3bb506024..f286ef5be 100644 --- a/addons/rose/addon/styles/rose/utilities/_button.scss +++ b/addons/rose/addon/styles/rose/utilities/_button.scss @@ -4,32 +4,39 @@ @mixin button { @include typography.type(button, semibold); - display: flex; - flex-direction: row; + display: inline-block; + margin-bottom: sizing.rems(l); + margin-right: sizing.rems(xs); padding: sizing.rems(off-xs) sizing.rems(l); border-radius: sizing.rems(xxxs); border: sizing.rems(xxxxs) solid; + background: none; - &.has-icon-left > .rose-icon:first-child { - margin-left: -(sizing.rems(xs)); - margin-right: sizing.rems(xxs); - } + .rose-button-wrapper { + display: flex; + flex-direction: row; - &.has-icon-right > .rose-icon:last-child { - margin-left: sizing.rems(xxs); - margin-right: -(sizing.rems(xs)); - } + &.has-icon-left > .rose-icon:first-child { + margin-left: -(sizing.rems(xs)); + margin-right: sizing.rems(xxs); + } - &.has-icon-only { - padding-right: sizing.rems(s); - padding-left: sizing.rems(s); - .rose-button-body { - position: absolute; - top: -1000px; - left: -1000px; - width: 1px; - height: 1px; - opacity: 0; + &.has-icon-right > .rose-icon:last-child { + margin-left: sizing.rems(xxs); + margin-right: -(sizing.rems(xs)); + } + + &.has-icon-only { + padding-right: sizing.rems(s); + padding-left: sizing.rems(s); + .rose-button-body { + position: absolute; + top: -1000px; + left: -1000px; + width: 1px; + height: 1px; + opacity: 0; + } } } } diff --git a/addons/rose/addon/templates/components/rose/button.hbs b/addons/rose/addon/templates/components/rose/button.hbs index f109c1407..a8ac2acbd 100644 --- a/addons/rose/addon/templates/components/rose/button.hbs +++ b/addons/rose/addon/templates/components/rose/button.hbs @@ -5,29 +5,30 @@ class="{{if @style (concat "rose-button-" @style)}} {{if @iconLeft "has-icon-left"}} {{if @iconRight "has-icon-right"}} {{if @iconOnly "has-icon-only"}}" > - {{#if @iconLeft}} - - {{/if}} + + {{#if @iconLeft}} + + {{/if}} - - {{yield}} + + {{yield}} + + + {{#if @iconOnly}} + + {{/if}} + + {{#if @iconRight}} + + {{/if}} - - {{#if @iconOnly}} - - {{/if}} - - {{#if @iconRight}} - - {{/if}} - diff --git a/addons/rose/addon/templates/components/rose/form/actions.hbs b/addons/rose/addon/templates/components/rose/form/actions.hbs new file mode 100644 index 000000000..47557fb7e --- /dev/null +++ b/addons/rose/addon/templates/components/rose/form/actions.hbs @@ -0,0 +1,19 @@ +
+ + {{@submitText}} + + + {{#if this.showCancel}} + + {{@cancelText}} + + {{/if}} +
diff --git a/addons/rose/app/components/rose/form/actions.js b/addons/rose/app/components/rose/form/actions.js new file mode 100644 index 000000000..debd30e78 --- /dev/null +++ b/addons/rose/app/components/rose/form/actions.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/form/actions'; diff --git a/addons/rose/tests/dummy/app/controllers/index.js b/addons/rose/tests/dummy/app/controllers/index.js index 3b56b102a..ff0929bb6 100644 --- a/addons/rose/tests/dummy/app/controllers/index.js +++ b/addons/rose/tests/dummy/app/controllers/index.js @@ -3,7 +3,7 @@ import { action } from '@ember/object'; export default class IndexController extends Controller { @action - selectChange(/*value*/) { + actionHandler(/*value*/) { // eslint-disable-next-line no-console //console.log(value); } diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index 400f1d6f1..40586ca08 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -50,7 +50,7 @@ Dummy app index template Choose an option @@ -63,12 +63,18 @@ Dummy app index template disabled={{true}} @label="Label" @helperText="Helper text" - @onChange={{fn this.selectChange}} + @onChange={{fn this.actionHandler}} as |select| > Choose an option +

Form Actions

+ + {}; + await render(hbs`{{rose/form/actions cancel=this.cancel}}`); + assert.ok(find('[type="submit"]')); + assert.ok(find('button:not([type="submit"])')); + }); + + test('it can disabled the buttons', async function (assert) { + assert.expect(2); + this.cancel = () => {}; + await render(hbs`{{rose/form/actions cancel=this.cancel disabled=true}}`); + assert.ok(find('[type="submit"]:disabled')); + assert.ok(find('button:not([type="submit"]):disabled')); + }); + + test('it optionally does not render the cancel button', async function (assert) { + assert.expect(2); + await render(hbs`{{rose/form/actions showCancel=false}}`); + assert.ok(find('[type="submit"]')); + assert.notOk(find('button:not([type="submit"])')); + }); + + test('it executes a function on cancel click', async function (assert) { + assert.expect(1); + this.cancel = () => assert.ok(true, 'cancel was clicked'); + await render(hbs`{{rose/form/actions cancel=this.cancel}}`); + await click('button:not([type="submit"])'); + }); +}); From 16f08744d35d1bf620269dbd39440e50a5f3291f Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 27 May 2020 17:28:29 -0400 Subject: [PATCH 02/10] =?UTF-8?q?chore:=20=F0=9F=A4=96=20add=20form=20comp?= =?UTF-8?q?onent=20for=20simpler=20form=20building?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/rose/addon/components/rose/form.js | 27 ++ .../addon/components/rose/form.stories.mdx | 126 ++++++++ .../components/rose/form/checkbox.stories.mdx | 4 +- .../components/rose/form/input.stories.mdx | 4 +- .../rose/form/radio/group.stories.mdx | 17 +- .../components/rose/form/select.stories.mdx | 4 +- .../components/rose/form/textarea.stories.mdx | 4 +- .../addon/templates/components/rose/form.hbs | 16 ++ .../components/rose/form/checkbox.hbs | 1 + .../templates/components/rose/form/input.hbs | 1 + .../components/rose/form/radio/group.hbs | 2 +- .../components/rose/form/radio/radio.hbs | 1 + .../templates/components/rose/form/select.hbs | 1 + .../components/rose/form/textarea.hbs | 3 +- addons/rose/app/components/rose/form.js | 1 + .../rose/tests/dummy/app/controllers/index.js | 4 +- .../rose/tests/dummy/app/templates/index.hbs | 270 ++++++++---------- .../integration/components/rose/form-test.js | 61 ++++ .../components/rose/form/checkbox-test.js | 4 +- .../components/rose/form/input-test.js | 2 +- .../components/rose/form/select-test.js | 2 +- .../components/rose/form/textarea-test.js | 2 +- 22 files changed, 389 insertions(+), 168 deletions(-) create mode 100644 addons/rose/addon/components/rose/form.js create mode 100644 addons/rose/addon/components/rose/form.stories.mdx create mode 100644 addons/rose/addon/templates/components/rose/form.hbs create mode 100644 addons/rose/app/components/rose/form.js create mode 100644 addons/rose/tests/integration/components/rose/form-test.js diff --git a/addons/rose/addon/components/rose/form.js b/addons/rose/addon/components/rose/form.js new file mode 100644 index 000000000..0805f0348 --- /dev/null +++ b/addons/rose/addon/components/rose/form.js @@ -0,0 +1,27 @@ +import Component from '@ember/component'; +import layout from '../../templates/components/rose/form'; +import { action } from '@ember/object'; + +/** + * A component for building accessible forms. Yields contextual fields + * and actions. + */ +export default Component.extend({ + layout, + tagName: '', + + // =actions + + /** + * Calls the passed `onSubmit` function and disabled the default form + * submit behavior. + * @param {Event} e + */ + @action + handleSubmit(e) { + e.preventDefault(); + e.stopPropagation(); + this.onSubmit(); + return false; + }, +}); diff --git a/addons/rose/addon/components/rose/form.stories.mdx b/addons/rose/addon/components/rose/form.stories.mdx new file mode 100644 index 000000000..73cb9ccc4 --- /dev/null +++ b/addons/rose/addon/components/rose/form.stories.mdx @@ -0,0 +1,126 @@ +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'; + + + +# Form + +A component for building accessible forms. Yields contextual fields +and actions. + +```htmlbars + + + + + Choose an option + Value 1 + Value 2 + Value 3 + + + + + + + + + +``` + + + {{ + template: hbs` + + + + + Choose an option + Value 1 + Value 2 + Value 3 + + + + + + + + + + `, + context: { + disabled: boolean('disabled', false), + submit: action('submit'), + cancel: action('cancel'), + selectChange: action('selectChange'), + }, + }} + diff --git a/addons/rose/addon/components/rose/form/checkbox.stories.mdx b/addons/rose/addon/components/rose/form/checkbox.stories.mdx index 3c342c827..3a47e9f8c 100644 --- a/addons/rose/addon/components/rose/form/checkbox.stories.mdx +++ b/addons/rose/addon/components/rose/form/checkbox.stories.mdx @@ -16,7 +16,7 @@ Renders a form input checkbox. @label="Yes?" @checked={{false}} @error={{false}} - disabled={{false}} + @disabled={{false}} /> ``` @@ -29,7 +29,7 @@ Renders a form input checkbox. @label={{label}} @checked={{checked}} @error={{error}} - disabled={{disabled}} + @disabled={{disabled}} /> `, context: { diff --git a/addons/rose/addon/components/rose/form/input.stories.mdx b/addons/rose/addon/components/rose/form/input.stories.mdx index c62620de7..0e7465be9 100644 --- a/addons/rose/addon/components/rose/form/input.stories.mdx +++ b/addons/rose/addon/components/rose/form/input.stories.mdx @@ -16,7 +16,7 @@ Renders a simple form input. @label="Email" @helperText="Enter your email" @error={{false}} - disabled={{false}} + @disabled={{false}} readonly={{false}} /> ``` @@ -30,7 +30,7 @@ Renders a simple form input. @label={{label}} @helperText={{helperText}} @error={{error}} - disabled={{disabled}} + @disabled={{disabled}} readonly={{read-only}} /> `, diff --git a/addons/rose/addon/components/rose/form/radio/group.stories.mdx b/addons/rose/addon/components/rose/form/radio/group.stories.mdx index af30e8246..ef99aa922 100644 --- a/addons/rose/addon/components/rose/form/radio/group.stories.mdx +++ b/addons/rose/addon/components/rose/form/radio/group.stories.mdx @@ -1,6 +1,6 @@ import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; import { hbs } from 'ember-cli-htmlbars'; -import { text } from '@storybook/addon-knobs'; +import { text, boolean } from '@storybook/addon-knobs'; @@ -9,7 +9,12 @@ import { text } from '@storybook/addon-knobs'; Renders a form radiofield group. ```htmlbars - + {{ template: hbs` - + @@ -34,7 +34,7 @@ Renders a form select element. @value={{value}} @label={{label}} @helperText={{helperText}} - disabled={{disabled}} + @disabled={{disabled}} @error={{error}} @onChange={{fn onChange}} as |select| diff --git a/addons/rose/addon/components/rose/form/textarea.stories.mdx b/addons/rose/addon/components/rose/form/textarea.stories.mdx index 8caffcdd8..17ae649f5 100644 --- a/addons/rose/addon/components/rose/form/textarea.stories.mdx +++ b/addons/rose/addon/components/rose/form/textarea.stories.mdx @@ -15,7 +15,7 @@ Renders a simple form textarea. @label="Description" @helperText="Enter a description" @error={{false}} - disabled={{false}} + @disabled={{false}} readonly={{false}} /> ``` @@ -28,7 +28,7 @@ Renders a simple form textarea. @label={{label}} @helperText={{helperText}} @error={{error}} - disabled={{disabled}} + @disabled={{disabled}} readonly={{read-only}} /> `, diff --git a/addons/rose/addon/templates/components/rose/form.hbs b/addons/rose/addon/templates/components/rose/form.hbs new file mode 100644 index 000000000..6c74ccae4 --- /dev/null +++ b/addons/rose/addon/templates/components/rose/form.hbs @@ -0,0 +1,16 @@ +
+ {{yield (hash + radioGroup=(component 'rose/form/radio/group' disabled=@disabled) + checkbox=(component 'rose/form/checkbox' disabled=@disabled) + input=(component 'rose/form/input' disabled=@disabled) + select=(component 'rose/form/select' disabled=@disabled) + textarea=(component 'rose/form/textarea' disabled=@disabled) + actions=(component 'rose/form/actions' disabled=@disabled cancel=@cancel) + )}} +
diff --git a/addons/rose/addon/templates/components/rose/form/checkbox.hbs b/addons/rose/addon/templates/components/rose/form/checkbox.hbs index ab2dec73b..b8d3f1dc5 100644 --- a/addons/rose/addon/templates/components/rose/form/checkbox.hbs +++ b/addons/rose/addon/templates/components/rose/form/checkbox.hbs @@ -4,6 +4,7 @@ ...attributes class="rose-form-checkbox-field" id={{@id}} + disabled={{@disabled}} @type="checkbox" @checked={{if @checked true false}} /> diff --git a/addons/rose/addon/templates/components/rose/form/input.hbs b/addons/rose/addon/templates/components/rose/form/input.hbs index fe8e86eed..9212c79df 100644 --- a/addons/rose/addon/templates/components/rose/form/input.hbs +++ b/addons/rose/addon/templates/components/rose/form/input.hbs @@ -12,6 +12,7 @@ ...attributes class="rose-form-input-field" id={{@id}} + disabled={{@disabled}} @type={{@type}} @value={{@value}} /> diff --git a/addons/rose/addon/templates/components/rose/form/radio/group.hbs b/addons/rose/addon/templates/components/rose/form/radio/group.hbs index 6aa52cf50..76cfea93b 100644 --- a/addons/rose/addon/templates/components/rose/form/radio/group.hbs +++ b/addons/rose/addon/templates/components/rose/form/radio/group.hbs @@ -1,3 +1,3 @@ {{yield (hash - radio=(component 'rose/form/radio/radio' name=@name selectedValue=@selectedValue) + radio=(component 'rose/form/radio/radio' name=@name selectedValue=@selectedValue disabled=@disabled) )}} diff --git a/addons/rose/addon/templates/components/rose/form/radio/radio.hbs b/addons/rose/addon/templates/components/rose/form/radio/radio.hbs index 088853d5b..ee54aa72c 100644 --- a/addons/rose/addon/templates/components/rose/form/radio/radio.hbs +++ b/addons/rose/addon/templates/components/rose/form/radio/radio.hbs @@ -5,6 +5,7 @@ @radioClass="rose-form-radio-field" @radioId={{@id}} type="radio" + disabled={{@disabled}} @name={{@name}} @value={{@value}} @groupValue={{@selectedValue}} diff --git a/addons/rose/addon/templates/components/rose/form/select.hbs b/addons/rose/addon/templates/components/rose/form/select.hbs index f7466ba0f..586e002a1 100644 --- a/addons/rose/addon/templates/components/rose/form/select.hbs +++ b/addons/rose/addon/templates/components/rose/form/select.hbs @@ -12,6 +12,7 @@ ...attributes class="rose-form-select-field" id={{@id}} + disabled={{@disabled}} @value={{@value}} @onChange={{@onChange}} as |xs| diff --git a/addons/rose/addon/templates/components/rose/form/textarea.hbs b/addons/rose/addon/templates/components/rose/form/textarea.hbs index 94017089a..317ebeea3 100644 --- a/addons/rose/addon/templates/components/rose/form/textarea.hbs +++ b/addons/rose/addon/templates/components/rose/form/textarea.hbs @@ -10,8 +10,9 @@