chore: 🤖 add select field component

This commit is contained in:
Randall Morey committed 2020-05-06 13:46:48 -04:00
1 parent ffb5d6e510
commit ff45fee2d1
12 files changed
+335 -2

No files matched your search

@@ -0,0 +1,27 @@
import Component from '@ember/component';
import layout from '../../../templates/components/rose/form/select';
/**
* A `<select>` element context component which yields option components.
*
* @example
* <Rose::Form::Select
* @id="select-id-1"
* name="select-field-name"
* @value="current-value"
* @label="Label"
* @helperText="Helper text"
* @error={{true}}
* @onChange={{fn this.selectChange}}
* disabled={{true}}
* as |select|
* >
* <select.option>Choose an option</select.option>
* <select.option @value="current-value">Curret value</select.option>
* </Rose::Form::Select>
*/
export default Component.extend({
layout,
tagName: '',
});
@@ -1,2 +1,3 @@
@import 'input';
@import 'checkbox';
@import 'select';
@@ -0,0 +1,69 @@
@use '../../variables/sizing';
@use '../../utilities/type';
.rose-form-select {
margin-bottom: sizing.rems(m);
.rose-form-select-label {
@include type.type(s, semibold);
display: block;
margin-bottom: sizing.rems(xxs);
}
.rose-form-select-helper-text {
@include type.type(xs);
display: block;
color: var(--ui-gray);
margin-bottom: sizing.rems(xxs);
}
.rose-form-select-field {
@include type.type(s);
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
vertical-align: middle;
display: inline-block;
padding: sizing.rems(xs) sizing.rems(xxl) sizing.rems(xs) sizing.rems(xs);
border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-2);
border-radius: sizing.rems(xxxs);
box-shadow: 0 $size-xxs $size-xxs
rgba(var(--stark-components), var(--opacity-2));
background: var(--ui-gray-subtler-5)
url('data:image/svg+xml;charset=utf8,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M12%205.83L15.17%209l1.41-1.41L12%203%207.41%207.59%208.83%209%2012%205.83zm0%2012.34L8.83%2015l-1.41%201.41L12%2021l4.59-4.59L15.17%2015%2012%2018.17z%22%20fill%3D%22%23525761%22%2F%3E%3C%2Fsvg%3E')
no-repeat right sizing.rems(xs) center;
background-size: sizing.rems(l);
&:not(:disabled) {
&:hover {
border-color: var(--ui-gray-subtler-1);
background-color: transparent;
box-shadow: none;
}
&:focus {
border-color: var(--info);
background-color: var(--ui-gray-subtler-5);
box-shadow: none;
}
}
&:disabled {
cursor: not-allowed;
color: var(--ui-gray-subtler-1);
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M12%205.83L15.17%209l1.41-1.41L12%203%207.41%207.59%208.83%209%2012%205.83zm0%2012.34L8.83%2015l-1.41%201.41L12%2021l4.59-4.59L15.17%2015%2012%2018.17z%22%20fill%3D%22%238E96A3%22%2F%3E%3C%2Fsvg%3E');
}
}
&.error {
color: var(--failure);
.rose-form-select-helper-text {
color: currentColor;
}
.rose-form-select-field {
border-color: var(--failure);
}
}
}
@@ -0,0 +1,22 @@
<div class="rose-form-select{{if @error " error"}}">
<label class="rose-form-select-label" for={{@id}}>
{{@label}}
</label>
{{#if @helperText}}
<span class="rose-form-select-helper-text">{{@helperText}}</span>
{{/if}}
<XSelect
...attributes
class="rose-form-select-field"
id={{@id}}
@value={{@value}}
@onChange={{@onChange}}
as |xs|
>
{{yield xs}}
</XSelect>
</div>
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/form/select';
+10
View File
@@ -0,0 +1,10 @@
import Controller from '@ember/controller';
import { action } from '@ember/object';
export default class IndexController extends Controller {
@action
selectChange(value) {
// eslint-disable-next-line no-console
console.log(value);
}
}
+22
View File
@@ -17,6 +17,28 @@ Dummy app index template
<br>
<h2>Form</h2>
<Rose::Form::Select
@label="Label"
@helperText="Helper text"
@onChange={{fn this.selectChange}}
as |select|
>
<select.option>Choose an option</select.option>
<select.option @value="value-1">Value 1</select.option>
<select.option @value="value-2">Value 2</select.option>
<select.option @value="value-3">Value 3</select.option>
</Rose::Form::Select>
<Rose::Form::Select
disabled={{true}}
@label="Label"
@helperText="Helper text"
@onChange={{fn this.selectChange}}
as |select|
>
<select.option>Choose an option</select.option>
</Rose::Form::Select>
<Rose::Form::Input
@label="Label"
@value="Read only"
+1
View File
@@ -63,6 +63,7 @@
"ember-source": "~3.12.0",
"ember-source-channel-url": "^2.0.1",
"ember-try": "^1.4.0",
"emberx-select": "github:adopted-ember-addons/emberx-select#bc5f774",
"eslint-plugin-ember": "^7.7.2",
"eslint-plugin-node": "^11.0.0",
"loader.js": "^4.7.0",
+1 -1
View File
@@ -12,7 +12,7 @@ export const Normal = () => ({
@submit={{submit}}
@disabled={{disabled}}
@style={{style}}
{{action onClick}}
{{on "click" onClick}}
>
{{text}}
</Rose::Button>
@@ -0,0 +1,45 @@
import { hbs } from 'ember-cli-htmlbars';
import { action } from '@storybook/addon-actions';
import { text, boolean, select } from '@storybook/addon-knobs';
export default {
title: 'Rose::Form::Select',
};
export const Normal = () => ({
template: hbs`
<Rose::Form::Select
@id={{id}}
@value={{value}}
@label={{label}}
@helperText={{helperText}}
disabled={{disabled}}
@error={{error}}
@onChange={{fn onChange}}
as |select|
>
<select.option>Choose an option</select.option>
<select.option @value="value-1">Value 1</select.option>
<select.option @value="value-2">Value 2</select.option>
<select.option @value="value-3">Value 3</select.option>
</Rose::Form::Select>
`,
context: {
value: select(
'value',
{
null: null,
'value-1': 'value-1',
'value-2': 'value-2',
'value-3': 'value-3',
},
null
),
id: text('id', 'field-id'),
label: text('label', 'Label'),
helperText: text('helperText', 'Helper text'),
disabled: boolean('disabled', false),
error: boolean('error', false),
onChange: action('changed'),
},
});
@@ -0,0 +1,104 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find, findAll, fillIn } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | rose/form/select', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
this.onChange = () => {};
await render(hbs`
<Rose::Form::Select
@label="Label"
@onChange={{fn this.onChange}}
as |select|
>
<select.option>Choose an option</select.option>
<select.option @value="value-1">Value 1</select.option>
<select.option @value="value-2">Value 2</select.option>
<select.option @value="value-3">Value 3</select.option>
</Rose::Form::Select>
`);
assert.equal(find('label').textContent.trim(), 'Label');
assert.ok(find('select'));
assert.equal(findAll('option').length, 4);
});
test('it displays optional helper text', async function (assert) {
this.onChange = () => {};
await render(hbs`
<Rose::Form::Select
@label="Label"
@helperText="Helper text"
@onChange={{fn this.onChange}}
as |select|
>
<select.option>Choose an option</select.option>
</Rose::Form::Select>
`);
assert.equal(
find('.rose-form-select-helper-text').textContent.trim(),
'Helper text'
);
});
test('it supports disabled attribute', async function (assert) {
this.onChange = () => {};
await render(hbs`
<Rose::Form::Select
@onChange={{fn this.onChange}}
disabled={{true}}
as |select|
>
<select.option>Choose an option</select.option>
</Rose::Form::Select>
`);
assert.ok(find('[disabled]'));
});
test('its value is bound to and udpated by @value', async function (assert) {
this.onChange = () => {};
this.value = 'value-1';
await render(hbs`
<Rose::Form::Select
@onChange={{fn this.onChange}}
@value={{value}}
as |select|
>
<select.option @value="value-1">value-1</select.option>
<select.option @value="value-2">value-2</select.option>
</Rose::Form::Select>
`);
assert.equal(find('select').value, 'value-1');
this.set('value', 'value-2');
assert.equal(find('select').value, 'value-2');
});
test('it triggers an action on change', async function (assert) {
assert.expect(2);
this.onChange1 = (value) => {
assert.equal(
value,
null,
'On initial render, onChange is triggered with null'
);
this.set('onChange', this.onChange2);
};
this.onChange2 = (value) => {
assert.equal(value, 'value-1', 'On change, value is passed in.');
};
this.onChange = this.onChange1;
await render(hbs`
<Rose::Form::Select
name="my-select"
@onChange={{fn this.onChange}}
as |select|
>
<select.option>Choose an option</select.option>
<select.option @value="value-1">value-1</select.option>
</Rose::Form::Select>
`);
await fillIn('[name="my-select"]', 'value-1');
});
});
+32 -1
View File
@@ -844,6 +844,18 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@bigtest/convergence@^1.1.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@bigtest/convergence/-/convergence-1.1.2.tgz#1028f28378aae6876b3c07e577a2d4a320ad0acf"
integrity sha512-f/tpOfdd5p40Omejmc+jwrNL0nZ0RDV2LEQQdIWYHtMdKfQQRQpdAhyfNVPLuLeKHw5D9dUX8v9WOrwGsMBTAw==
"@bigtest/interactor@^0.9.0":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@bigtest/interactor/-/interactor-0.9.3.tgz#f83fa868fc5742a482114af15d22f50677d3a81f"
integrity sha512-MKbhp/j1TtlSp1kIM1btvPrMbxn1eW2Notd5oUChBtEpnm8FDAiZIg6LED1aTsUxyRWf2qb5RlJyoy9HZjRgzQ==
dependencies:
"@bigtest/convergence" "^1.1.1"
"@cnakazawa/watch@^1.0.3":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
@@ -6163,7 +6175,7 @@ ember-assign-polyfill@^2.6.0:
ember-cli-babel "^6.16.0"
ember-cli-version-checker "^2.0.0"
ember-auto-import@^1.5.3:
ember-auto-import@^1.2.15, ember-auto-import@^1.5.3:
version "1.5.3"
resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-1.5.3.tgz#b32936f874d1ed7057ad2ed3f6116357820be44b"
integrity sha512-7JfdunM1BmLy/lyUXu7uEoi0Gi4+dxkGM23FgIEyW5g7z4MidhP53Fc61t49oPSnq7+J4lLpbH1f6C+mDMgb4A==
@@ -6302,6 +6314,16 @@ ember-cli-htmlbars-inline-precompile@^2.1.0:
heimdalljs-logger "^0.1.9"
silent-error "^1.1.0"
ember-cli-htmlbars@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-3.1.0.tgz#87806c2a0bca2ab52d4fb8af8e2215c1ca718a99"
integrity sha512-cgvRJM73IT0aePUG7oQ/afB7vSRBV3N0wu9BrWhHX2zkR7A7cUBI7KC9VPk6tbctCXoM7BRGsCC4aIjF7yrfXA==
dependencies:
broccoli-persistent-filter "^2.3.1"
hash-for-dep "^1.5.1"
json-stable-stringify "^1.0.1"
strip-bom "^3.0.0"
ember-cli-htmlbars@^4.0.0, ember-cli-htmlbars@^4.2.2:
version "4.3.1"
resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-4.3.1.tgz#4af8adc21ab3c4953f768956b7f7d207782cb175"
@@ -6749,6 +6771,15 @@ ember-try@^1.4.0:
rsvp "^4.7.0"
walk-sync "^1.1.3"
"emberx-select@github:adopted-ember-addons/emberx-select#bc5f774":
version "4.0.0-beta.2"
resolved "https://codeload.github.com/adopted-ember-addons/emberx-select/tar.gz/bc5f7746ae67d13e17fe2bd118cbed99b0e10aa2"
dependencies:
"@bigtest/interactor" "^0.9.0"
ember-auto-import "^1.2.15"
ember-cli-babel "^6.16.0"
ember-cli-htmlbars "^3.0.0"
emit-function@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/emit-function/-/emit-function-0.0.2.tgz#e3a50b3d61be1bf8ca88b924bf713157a5bec124"