From 10fddd9027f28c1bdfdab903d067377211536d76 Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Thu, 23 Feb 2017 15:27:36 +0100 Subject: [PATCH] Enhance customizability paper-{form, input, radio-group} Components yielded by paper-form, paper-input and paper-radio-group are now customizable which makes it easier to use custom components side-by-side with ember-paper ones. --- addon/components/paper-form.js | 6 + addon/components/paper-input.js | 3 + addon/components/paper-radio-group.js | 2 + addon/templates/components/paper-form.hbs | 8 +- addon/templates/components/paper-input.hbs | 4 +- .../components/paper-radio-group.hbs | 2 +- .../integration/components/paper-form-test.js | 130 ++++++++++++++++++ .../components/paper-input-test.js | 31 ++++- .../components/paper-radio-group-test.js | 18 ++- 9 files changed, 195 insertions(+), 9 deletions(-) diff --git a/addon/components/paper-form.js b/addon/components/paper-form.js index 30c87bc8f..dd0cf8796 100644 --- a/addon/components/paper-form.js +++ b/addon/components/paper-form.js @@ -15,6 +15,12 @@ const { Component, computed } = Ember; export default Component.extend(ParentMixin, { layout, tagName: 'form', + + inputComponent: 'paper-input', + submitButtonComponent: 'paper-button', + selectComponent: 'paper-select', + autocompleteComponent: 'paper-autocomplete', + isValid: computed.not('isInvalid'), isInvalid: computed('childComponents.@each.isInvalid', function() { return this.get('childComponents').isAny('isInvalid'); diff --git a/addon/components/paper-input.js b/addon/components/paper-input.js index 57cbfeca7..ae2fbe887 100644 --- a/addon/components/paper-input.js +++ b/addon/components/paper-input.js @@ -35,6 +35,9 @@ export default Component.extend(FocusableMixin, ColorMixin, ChildMixin, Validati tabindex: null, hideAllMessages: false, isTouched: false, + + iconComponent: 'paper-icon', + isInvalid: computed.or('validationErrorMessages.length', 'isNativeInvalid'), hasValue: computed('value', 'isNativeInvalid', function() { let value = this.get('value'); diff --git a/addon/components/paper-radio-group.js b/addon/components/paper-radio-group.js index 20b4162a3..f4c922a23 100644 --- a/addon/components/paper-radio-group.js +++ b/addon/components/paper-radio-group.js @@ -22,6 +22,8 @@ export default Component.extend(FocusableMixin, ParentMixin, { /* FocusableMixin Overrides */ focusOnlyOnKey: true, + radioComponent: 'paper-radio', + constants: inject.service(), // Lifecycle hooks diff --git a/addon/templates/components/paper-form.hbs b/addon/templates/components/paper-form.hbs index 08d3e0cac..5633ee31e 100644 --- a/addon/templates/components/paper-form.hbs +++ b/addon/templates/components/paper-form.hbs @@ -1,18 +1,18 @@ {{yield (hash isValid=isValid isInvalid=isInvalid - input=(component "paper-input" + input=(component inputComponent parentComponent=this onValidityChange=(action "onValidityChange") ) - submit-button=(component "paper-button" + submit-button=(component submitButtonComponent type="submit" ) - select=(component "paper-select" + select=(component selectComponent parentComponent=this onValidityChange=(action "onValidityChange") ) - autocomplete=(component "paper-autocomplete" + autocomplete=(component autocompleteComponent parentComponent=this onValidityChange=(action "onValidityChange") ) diff --git a/addon/templates/components/paper-input.hbs b/addon/templates/components/paper-input.hbs index c1c692bb6..0c110770a 100644 --- a/addon/templates/components/paper-input.hbs +++ b/addon/templates/components/paper-input.hbs @@ -3,7 +3,7 @@ {{/if}} {{#if icon}} - {{paper-icon icon}} + {{component iconComponent icon}} {{/if}} {{#if textarea}} @@ -101,5 +101,5 @@ )}} {{#if iconRight}} - {{paper-icon iconRight}} + {{component iconComponent iconRight}} {{/if}} diff --git a/addon/templates/components/paper-radio-group.hbs b/addon/templates/components/paper-radio-group.hbs index c84c34876..8332c5544 100644 --- a/addon/templates/components/paper-radio-group.hbs +++ b/addon/templates/components/paper-radio-group.hbs @@ -1,5 +1,5 @@ {{yield (hash - radio=(component "paper-radio" + radio=(component radioComponent toggle=toggle disabled=disabled groupValue=groupValue diff --git a/tests/integration/components/paper-form-test.js b/tests/integration/components/paper-form-test.js index eada4ba5d..0d3198853 100644 --- a/tests/integration/components/paper-form-test.js +++ b/tests/integration/components/paper-form-test.js @@ -1,6 +1,9 @@ +import Ember from 'ember'; import { moduleForComponent, test } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; +const { Component } = Ember; + moduleForComponent('paper-form', 'Integration | Component | paper form', { integration: true }); @@ -182,6 +185,22 @@ test('form submit button is of type submit', function(assert) { assert.equal(this.$('button').attr('type'), 'submit'); }); +test('form submit button component can be customized by passing `submitButtonComponent`', function(assert) { + assert.expect(1); + + this.register('component:custom-submit-button', Component.extend({ + classNames: ['custom-submit-button'] + })); + + this.render(hbs` + {{#paper-form submitButtonComponent="custom-submit-button" as |form|}} + {{form.submit-button}} + {{/paper-form}} + `); + + assert.equal(this.$('.custom-submit-button').length, 1, 'custom submit button is displayed'); +}); + test('form `onSubmit` action is invoked when form element is submitted', function(assert) { assert.expect(1); @@ -201,3 +220,114 @@ test('form `onSubmit` action is invoked when form element is submitted', functio this.$('input').last().click(); }); + +test('yielded form.input renders the `paper-input`-component', function(assert) { + assert.expect(1); + + this.register('component:paper-input', Component.extend({ + classNames: ['paper-input'] + })); + + this.render(hbs` + {{#paper-form as |form|}} + {{form.input}} + {{/paper-form}} + `); + + assert.equal(this.$('.paper-input').length, 1, 'paper-input component displayed'); +}); + +test('yielded form.input can be customized by passing `inputComponent`', function(assert) { + assert.expect(2); + + this.register('component:paper-input', Component.extend({ + classNames: ['paper-input'] + })); + + this.register('component:custom-input', Component.extend({ + classNames: ['custom-input'] + })); + + this.render(hbs` + {{#paper-form inputComponent="custom-input" as |form|}} + {{form.input}} + {{/paper-form}} + `); + + assert.equal(this.$('.paper-input').length, 0, 'paper-input component is not displayed'); + assert.equal(this.$('.custom-input').length, 1, 'custom input-component is displayed'); +}); + +test('yielded form.select renders `paper-select`-component', function(assert) { + assert.expect(1); + + this.register('component:paper-select', Component.extend({ + classNames: ['paper-select'] + })); + + this.render(hbs` + {{#paper-form as |form|}} + {{form.select}} + {{/paper-form}} + `); + + assert.equal(this.$('.paper-select').length, 1, 'paper-select is displayed'); +}); + +test('yielded form.select can be customized by passing `selectComponent`', function(assert) { + assert.expect(2); + + this.register('component:paper-select', Component.extend({ + classNames: ['paper-select'] + })); + + this.register('component:custom-select', Component.extend({ + classNames: ['custom-select'] + })); + + this.render(hbs` + {{#paper-form selectComponent="custom-select" as |form|}} + {{form.select}} + {{/paper-form}} + `); + + assert.equal(this.$('.paper-select').length, 0, 'paper-select component is not displayed'); + assert.equal(this.$('.custom-select').length, 1, 'custom select-component is displayed'); +}); + +test('yielded form.autocomplete renders `paper-autocomplete`-component', function(assert) { + assert.expect(1); + + this.register('component:paper-autocomplete', Component.extend({ + classNames: ['paper-autocomplete'] + })); + + this.render(hbs` + {{#paper-form as |form|}} + {{form.autocomplete}} + {{/paper-form}} + `); + + assert.equal(this.$('.paper-autocomplete').length, 1, 'paper-autocomplete is displayed'); +}); + +test('yielded form.autocomplete can be customized by passing `autocompleteComponent`', function(assert) { + assert.expect(2); + + this.register('component:paper-autocomplete', Component.extend({ + classNames: ['paper-autocomplete'] + })); + + this.register('component:custom-autocomplete', Component.extend({ + classNames: ['custom-autocomplete'] + })); + + this.render(hbs` + {{#paper-form autocompleteComponent="custom-autocomplete" as |form|}} + {{form.autocomplete}} + {{/paper-form}} + `); + + assert.equal(this.$('.paper-autocomplete').length, 0, 'paper-autocomplete component is not displayed'); + assert.equal(this.$('.custom-autocomplete').length, 1, 'custom autocomplete-component is displayed'); +}); diff --git a/tests/integration/components/paper-input-test.js b/tests/integration/components/paper-input-test.js index fc73fdf03..3fdb11116 100644 --- a/tests/integration/components/paper-input-test.js +++ b/tests/integration/components/paper-input-test.js @@ -1,7 +1,10 @@ +import Ember from 'ember'; import { moduleForComponent, test } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; import wait from 'ember-test-helpers/wait'; +const { Component } = Ember; + moduleForComponent('paper-input', 'Integration | Component | paper input', { integration: true, beforeEach() { @@ -36,6 +39,32 @@ test('renders with right icon', function(assert) { assert.ok(this.$('md-input-container').hasClass('md-icon-right')); }); +test('renders with a custom icon component when `iconComponent` is specified', function(assert) { + assert.expect(2); + + this.register('component:custom-icon', Component.extend({ + classNames: ['custom-icon'] + })); + + this.render(hbs`{{paper-input iconComponent="custom-icon" icon="person" onChange=dummyOnChange}}`); + + assert.equal(this.$('md-input-container md-icon').length, 0, 'default icon component is not rendered'); + assert.equal(this.$('md-input-container .custom-icon').length, 1, 'custom icon component rendered'); +}); + +test('renders with a custom icon component when `iconComponent` is specified and icon should be displayed on the right', function(assert) { + assert.expect(2); + + this.register('component:custom-icon', Component.extend({ + classNames: ['custom-icon'] + })); + + this.render(hbs`{{paper-input iconComponent="custom-icon" iconRight="person" onChange=dummyOnChange}}`); + + assert.equal(this.$('md-input-container md-icon').length, 0, 'default icon component is not rendered'); + assert.equal(this.$('md-input-container .custom-icon').length, 1, 'custom icon component rendered'); +}); + test('renders input with id', function(assert) { assert.expect(1); @@ -578,4 +607,4 @@ test('can render other stuff using paper-input block', function(assert) { `); assert.equal(this.$('.other-stuff').length, 1); -}); \ No newline at end of file +}); diff --git a/tests/integration/components/paper-radio-group-test.js b/tests/integration/components/paper-radio-group-test.js index 274c991a8..1ec94ce6c 100644 --- a/tests/integration/components/paper-radio-group-test.js +++ b/tests/integration/components/paper-radio-group-test.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import { moduleForComponent, test } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; -const { run, $: jQuery } = Ember; +const { Component, run, $: jQuery } = Ember; moduleForComponent('paper-group-radio', 'Integration | Component | paper radio group', { integration: true @@ -186,3 +186,19 @@ test('the `onChange` action is mandatory for paper-radio-group', function(assert `); }, /requires an `onChange` action/); }); + +test('passing `radioComponent` allows customizing the yielded radio-component', function(assert) { + assert.expect(1); + + this.register('component:custom-radio', Component.extend({ + classNames: 'custom-radio' + })); + + this.render(hbs` + {{#paper-radio-group radioComponent="custom-radio" groupValue=groupValue onChange=null as |group|}} + {{group.radio}} + {{/paper-radio-group}} + `); + + assert.equal(this.$('.custom-radio').length, 1, 'custom radio component is displayed'); +});