Merge branch 'develop' into ICU-177-master-layout
This commit is contained in:
70 files changed
+1487
-438
No files matched your search
@@ -21,7 +21,8 @@ module.exports = {
|
||||
browser: true
|
||||
},
|
||||
rules: {
|
||||
'ember/no-jquery': 'error'
|
||||
'ember/no-jquery': 'error',
|
||||
'ember/no-new-mixins': 0
|
||||
},
|
||||
overrides: [
|
||||
// node files
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,123 @@
|
||||
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|Form" component="Form" />
|
||||
|
||||
# Form
|
||||
|
||||
A component for building accessible forms. Yields contextual fields
|
||||
and actions.
|
||||
|
||||
<Preview>
|
||||
<Story name="Form" height="35rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form
|
||||
@onSubmit={{submit}}
|
||||
@cancel={{cancel}}
|
||||
@disabled={{disabled}}
|
||||
as |form|>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.select
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{selectChange}}
|
||||
as |field|
|
||||
>
|
||||
<field.field 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>
|
||||
</field.field>
|
||||
</form.select>
|
||||
<form.radioGroup @name="color" @selectedValue="green" as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@label="Red"
|
||||
@value="red"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Green"
|
||||
@value="green"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Blue"
|
||||
@value="blue"
|
||||
/>
|
||||
</form.radioGroup>
|
||||
<form.checkbox
|
||||
@label="Label"
|
||||
@checked={{true}}
|
||||
/>
|
||||
<form.actions @submitText="Save" @cancelText="Cancel" @showCancel={{true}} />
|
||||
</Rose::Form>
|
||||
`,
|
||||
context: {
|
||||
disabled: boolean('disabled', false),
|
||||
submit: action('submit'),
|
||||
cancel: action('cancel'),
|
||||
selectChange: action('selectChange'),
|
||||
},
|
||||
}}</Story>
|
||||
</Preview>
|
||||
|
||||
|
||||
```htmlbars
|
||||
<Rose::Form
|
||||
@onSubmit={{this.submit}}
|
||||
@cancel={{this.cancel}}
|
||||
@disabled={{false}}
|
||||
as |form|>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.select
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.actionHandler}}
|
||||
as |field|
|
||||
>
|
||||
<field.field 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>
|
||||
</field.field>
|
||||
</form.select>
|
||||
<form.radioGroup @name="color" @selectedValue="green" as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@label="Red"
|
||||
@value="red"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Green"
|
||||
@value="green"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Blue"
|
||||
@value="blue"
|
||||
/>
|
||||
</form.radioGroup>
|
||||
<form.checkbox
|
||||
@label="Label"
|
||||
/>
|
||||
<form.actions @submitText="Save" @cancelText="Cancel" @showCancel={{true}} />
|
||||
</Rose::Form>
|
||||
```
|
||||
@@ -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
|
||||
* <Rose::Form::Actions
|
||||
* @submitText="Save"
|
||||
* @cancelText="Cancel"
|
||||
* @showCancel={{true}}
|
||||
* @cancel=(fn @cancel) />
|
||||
*/
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
showCancel: true,
|
||||
});
|
||||
@@ -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';
|
||||
|
||||
<Meta title="Rose|Form/Actions" component="Form/Actions" />
|
||||
|
||||
# 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
|
||||
<Rose::Form::Actions
|
||||
@submitText="Save"
|
||||
@cancelText="Cancel"
|
||||
@showCancel={{true}}
|
||||
@disabled={{false}}
|
||||
@cancel=(fn @cancel) />
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Form Actions">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Actions
|
||||
@submitText={{submitText}}
|
||||
@cancelText={{cancelText}}
|
||||
@showCancel={{showCancel}}
|
||||
@disabled={{disabled}}
|
||||
@cancel={{onCancel}} />
|
||||
`,
|
||||
context: {
|
||||
submitText: text('submitText', 'Save'),
|
||||
cancelText: text('cancelText', 'Cancel'),
|
||||
showCancel: boolean('showCancel', true),
|
||||
disabled: boolean('disabled', false),
|
||||
onCancel: action('cancel'),
|
||||
},
|
||||
}}</Story>
|
||||
</Preview>
|
||||
@@ -1,21 +1,11 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/form/checkbox';
|
||||
import ComponentAutoId from '../../../mixins/component-auto-id';
|
||||
|
||||
/**
|
||||
* A simple HTML `<input type="checkbox">` element.
|
||||
*
|
||||
* @example
|
||||
* <Rose::Form::Checkbox
|
||||
* @label="Label"
|
||||
* @id="fieldId"
|
||||
* name="fieldName"
|
||||
* disabled={{true}}
|
||||
* @error={{true}}
|
||||
* @checked={{true}}
|
||||
* />
|
||||
*/
|
||||
export default Component.extend({
|
||||
export default Component.extend(ComponentAutoId, {
|
||||
layout,
|
||||
|
||||
tagName: '',
|
||||
});
|
||||
@@ -11,30 +11,27 @@ Renders a form input checkbox.
|
||||
|
||||
```htmlbars
|
||||
<Rose::Form::Checkbox
|
||||
@id="form-field-1"
|
||||
name="boolean-value"
|
||||
@label="Yes?"
|
||||
@checked={{false}}
|
||||
@error={{false}}
|
||||
disabled={{false}}
|
||||
@disabled={{false}}
|
||||
/>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic" height="10rem">{{
|
||||
<Story name="Basic Checkbox" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Checkbox
|
||||
@id={{id}}
|
||||
name={{name}}
|
||||
@label={{label}}
|
||||
@checked={{checked}}
|
||||
@error={{error}}
|
||||
disabled={{disabled}}
|
||||
@disabled={{disabled}}
|
||||
/>
|
||||
`,
|
||||
context: {
|
||||
label: text('text', 'Checkbox 🛎'),
|
||||
id: text('id', 'checkbox-1'),
|
||||
name: text('name', 'checkbox-1'),
|
||||
checked: boolean('checked', false),
|
||||
error: boolean('error', false),
|
||||
@@ -42,3 +39,28 @@ Renders a form input checkbox.
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview>
|
||||
<Story name="Checkbox with errors" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Checkbox
|
||||
name={{name}}
|
||||
@label={{label}}
|
||||
@checked={{checked}}
|
||||
@error={{true}}
|
||||
@disabled={{disabled}}
|
||||
as |field|
|
||||
>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Checkbox>
|
||||
`,
|
||||
context: {
|
||||
label: text('text', 'Checkbox 🛎'),
|
||||
name: text('name', 'checkbox-1'),
|
||||
checked: boolean('checked', false),
|
||||
disabled: boolean('disabled', false),
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
@@ -0,0 +1,10 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/form/errors';
|
||||
|
||||
/**
|
||||
* A container for error messages. Yields the error message component.
|
||||
*/
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
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';
|
||||
|
||||
<Meta title="Rose|Form/Errors" component="Form/Errors" />
|
||||
|
||||
# Form Errors
|
||||
|
||||
Use this component to display one or more error messages.
|
||||
|
||||
```html
|
||||
<Rose::Form::Errors as |errors|>
|
||||
<errors.message>An error message goes here.</errors.message>
|
||||
<errors.message>Another message goes here.</errors.message>
|
||||
</Rose::Form::Errors>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Form Errors">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Errors as |errors|>
|
||||
<errors.message>An error message goes here.</errors.message>
|
||||
<errors.message>Another message goes here.</errors.message>
|
||||
</Rose::Form::Errors>
|
||||
`,
|
||||
context: {},
|
||||
}}</Story>
|
||||
</Preview>
|
||||
@@ -0,0 +1,10 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../../templates/components/rose/form/errors/message';
|
||||
|
||||
/**
|
||||
* A simple, styled error message. Do not use directly.
|
||||
*/
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
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';
|
||||
|
||||
<Meta title="Rose|Form/Errors/Message" component="Form/Errors/Message" />
|
||||
|
||||
# Form Error Message
|
||||
|
||||
This component accepts block content describing a single error to the user.
|
||||
Normally this component would not be used directly, but rather in the context
|
||||
of the `Rose::Form::Errors` component.
|
||||
|
||||
```html
|
||||
<Rose::Form::Errors::Message>
|
||||
An error message goes here.
|
||||
</Rose::Form::Errors::Message>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Form Error Message">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Errors::Message>
|
||||
An error message goes here.
|
||||
</Rose::Form::Errors::Message>
|
||||
`,
|
||||
context: {},
|
||||
}}</Story>
|
||||
</Preview>
|
||||
@@ -1,22 +1,11 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/form/input';
|
||||
import ComponentAutoId from '../../../mixins/component-auto-id';
|
||||
|
||||
/**
|
||||
* A simple HTML `<input>` element.
|
||||
*
|
||||
* @example
|
||||
* <Rose::Form::Input
|
||||
* @id="fieldId"
|
||||
* @type="text"
|
||||
* @value="Text"
|
||||
* @label="Label"
|
||||
* @helperText="Helper text"
|
||||
* @error={{true}}
|
||||
* disabled={{true}}
|
||||
* readonly={{true}}
|
||||
* />
|
||||
*/
|
||||
export default Component.extend({
|
||||
export default Component.extend(ComponentAutoId, {
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -16,21 +16,21 @@ Renders a simple form input.
|
||||
@label="Email"
|
||||
@helperText="Enter your email"
|
||||
@error={{false}}
|
||||
disabled={{false}}
|
||||
@disabled={{false}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic">{{
|
||||
<Story name="Basic Field">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Input
|
||||
@type={{type}}
|
||||
@value={{value}}
|
||||
@label={{label}}
|
||||
@helperText={{helperText}}
|
||||
@error={{error}}
|
||||
disabled={{disabled}}
|
||||
@error={{false}}
|
||||
@disabled={{disabled}}
|
||||
readonly={{read-only}}
|
||||
/>
|
||||
`,
|
||||
@@ -50,7 +50,44 @@ Renders a simple form input.
|
||||
helperText: text('helperText', 'Helper text'),
|
||||
disabled: boolean('disabled', false),
|
||||
'read-only': boolean('readonly', false),
|
||||
error: boolean('error', false),
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview>
|
||||
<Story name="Field with Errors">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Input
|
||||
@type={{type}}
|
||||
@value={{value}}
|
||||
@label={{label}}
|
||||
@helperText={{helperText}}
|
||||
@error={{true}}
|
||||
@disabled={{disabled}}
|
||||
readonly={{read-only}}
|
||||
as |field|
|
||||
>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Input>
|
||||
`,
|
||||
context: {
|
||||
type: select(
|
||||
'type',
|
||||
{
|
||||
text: 'text',
|
||||
email: 'email',
|
||||
number: 'number',
|
||||
password: 'password',
|
||||
},
|
||||
'text'
|
||||
),
|
||||
value: text('value', 'Value'),
|
||||
label: text('label', 'Label'),
|
||||
helperText: text('helperText', 'Helper text'),
|
||||
disabled: boolean('disabled', false),
|
||||
'read-only': boolean('readonly', false),
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
@@ -3,29 +3,8 @@ import layout from '../../../../templates/components/rose/form/radio/group';
|
||||
|
||||
/**
|
||||
* A `<input type="radio" name="radio-group">` element.
|
||||
*
|
||||
* @example
|
||||
* <Rose::Form::Radio::Group @name="color" @selectedValue="green" as |radioGroup|>
|
||||
* <radioGroup.radio
|
||||
* @id="red-radio"
|
||||
* @label="Red"
|
||||
* @value="red"
|
||||
* />
|
||||
* <radioGroup.radio
|
||||
* @id="green-radio"
|
||||
* @label="Green"
|
||||
* @value="green"
|
||||
* />
|
||||
* <radioGroup.radio
|
||||
* @id="blue-radio"
|
||||
* @label="Blue"
|
||||
* @value="blue"
|
||||
* />
|
||||
* </Rose::Form::Radio::Group>
|
||||
*/
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
|
||||
tagName: '',
|
||||
});
|
||||
@@ -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';
|
||||
|
||||
<Meta title="Rose|Form/Radio/Group" component="Form/Radio/Group" />
|
||||
|
||||
@@ -9,19 +9,21 @@ import { text } from '@storybook/addon-knobs';
|
||||
Renders a form radiofield group.
|
||||
|
||||
```htmlbars
|
||||
<Rose::Form::Radio::Group @name={{name}} @selectedValue="disagree" as |radioGroup|>
|
||||
<Rose::Form::Radio::Group
|
||||
@disabled={{false}}
|
||||
@name={{name}}
|
||||
@selectedValue="disagree"
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.radio
|
||||
@id="agree-radiofield"
|
||||
@label="Agree"
|
||||
@value="agree"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="disagree-radiofield"
|
||||
@label="disagree"
|
||||
@value="disagree"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="maybe-radiofield"
|
||||
@label="maybe"
|
||||
@value="maybe"
|
||||
/>
|
||||
@@ -30,19 +32,21 @@ Renders a form radiofield group.
|
||||
<Preview>
|
||||
<Story name="Basic" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Radio::Group @name={{name}} @selectedValue={{selectedValue}} as |radioGroup|>
|
||||
<Rose::Form::Radio::Group
|
||||
@disabled={{disabled}}
|
||||
@name={{name}}
|
||||
@selectedValue={{selectedValue}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.radio
|
||||
@id="firstField"
|
||||
@label={{firstFieldLabel}}
|
||||
@value={{firstFieldValue}}
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="secondField"
|
||||
@label={{secondFieldLabel}}
|
||||
@value={{secondFieldValue}}
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="thirdField"
|
||||
@label={{thirdFieldLabel}}
|
||||
@value={{thirdFieldValue}}
|
||||
/>
|
||||
@@ -50,6 +54,7 @@ Renders a form radiofield group.
|
||||
`,
|
||||
context: {
|
||||
name: text('name', 'mustagree'),
|
||||
disabled: boolean('disabled', false),
|
||||
selectedValue: text('selectedValue', 'disagree'),
|
||||
firstFieldLabel: text('first label', 'Agree'),
|
||||
firstFieldValue: text('first value', 'agree'),
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../../templates/components/rose/form/radio/radio';
|
||||
import ComponentAutoId from '../../../../mixins/component-auto-id';
|
||||
|
||||
/**
|
||||
* A `<input type="radio">` element.
|
||||
* `value` and `selectedValue` must be equal to select
|
||||
* radiofield.
|
||||
*
|
||||
* @example
|
||||
* <Rose::Form::Radio::Radio
|
||||
* @id="fieldId"
|
||||
* @label="label"
|
||||
* @error={{true}}
|
||||
* @value="fieldValue"
|
||||
* @selectedValue="fieldValue"
|
||||
* @disabled={{true}}
|
||||
* />
|
||||
*/
|
||||
export default Component.extend({
|
||||
export default Component.extend(ComponentAutoId, {
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -10,7 +10,6 @@ Renders a form radiofield.
|
||||
|
||||
```htmlbars
|
||||
<Rose::Form::Radio::Radio
|
||||
@id="yes-radiofield"
|
||||
@label="Yes"
|
||||
@error={{false}}
|
||||
@value="yes-agree"
|
||||
@@ -23,7 +22,6 @@ Renders a form radiofield.
|
||||
<Story name="Basic" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Radio::Radio
|
||||
@id={{id}}
|
||||
@label={{label}}
|
||||
@error={{error}}
|
||||
@value={{value}}
|
||||
@@ -32,7 +30,6 @@ Renders a form radiofield.
|
||||
/>
|
||||
`,
|
||||
context: {
|
||||
id: text('id', 'radio-1'),
|
||||
label: text('text', 'Radiofield'),
|
||||
error: boolean('error', false),
|
||||
value: text('value', 'value and selectedValue must match to select radiofield'),
|
||||
|
||||
@@ -1,27 +1,11 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/form/select';
|
||||
import ComponentAutoId from '../../../mixins/component-auto-id';
|
||||
|
||||
/**
|
||||
* 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({
|
||||
export default Component.extend(ComponentAutoId, {
|
||||
layout,
|
||||
|
||||
tagName: '',
|
||||
});
|
||||
@@ -11,18 +11,20 @@ Renders a form select element.
|
||||
|
||||
```htmlbars
|
||||
<Rose::Form::Select
|
||||
@id="select-id"
|
||||
@name="select-name"
|
||||
@value="green"
|
||||
@label="Color"
|
||||
@helperText="Set your desired color"
|
||||
disabled={{false}}
|
||||
@disabled={{false}}
|
||||
@error={{false}}
|
||||
as |select|
|
||||
as |field|
|
||||
>
|
||||
<select.option>Choose a color</select.option>
|
||||
<select.option @value="red">Red</select.option>
|
||||
<select.option @value="green">Green</select.option>
|
||||
<select.option @value="blue">Blue</select.option>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose a color</select.option>
|
||||
<select.option @value="red">Red</select.option>
|
||||
<select.option @value="green">Green</select.option>
|
||||
<select.option @value="blue">Blue</select.option>
|
||||
</field.field>
|
||||
</Rose::Form::Select>
|
||||
```
|
||||
|
||||
@@ -30,19 +32,21 @@ Renders a form select element.
|
||||
<Story name="Basic" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Select
|
||||
@id={{id}}
|
||||
@name={{name}}
|
||||
@value={{value}}
|
||||
@label={{label}}
|
||||
@helperText={{helperText}}
|
||||
disabled={{disabled}}
|
||||
@error={{error}}
|
||||
@disabled={{disabled}}
|
||||
@error={{false}}
|
||||
@onChange={{fn onChange}}
|
||||
as |select|
|
||||
as |field|
|
||||
>
|
||||
<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>
|
||||
<field.field 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>
|
||||
</field.field>
|
||||
</Rose::Form::Select>
|
||||
`,
|
||||
context: {
|
||||
@@ -56,11 +60,54 @@ Renders a form select element.
|
||||
},
|
||||
null
|
||||
),
|
||||
id: text('id', 'field-id'),
|
||||
name: text('name', 'select-name'),
|
||||
label: text('label', 'Label'),
|
||||
helperText: text('helperText', 'Helper text'),
|
||||
disabled: boolean('disabled', false),
|
||||
onChange: action('changed'),
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview>
|
||||
<Story name="Select with Errors" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Select
|
||||
@name={{name}}
|
||||
@value={{value}}
|
||||
@label={{label}}
|
||||
@helperText={{helperText}}
|
||||
@disabled={{disabled}}
|
||||
@error={{true}}
|
||||
@onChange={{fn onChange}}
|
||||
as |field|
|
||||
>
|
||||
<field.field 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>
|
||||
</field.field>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Select>
|
||||
`,
|
||||
context: {
|
||||
value: select(
|
||||
'value',
|
||||
{
|
||||
null: null,
|
||||
'value-1': 'value-1',
|
||||
'value-2': 'value-2',
|
||||
'value-3': 'value-3',
|
||||
},
|
||||
null
|
||||
),
|
||||
name: text('name', 'select-name'),
|
||||
label: text('label', 'Label'),
|
||||
helperText: text('helperText', 'Helper text'),
|
||||
disabled: boolean('disabled', false),
|
||||
error: boolean('error', false),
|
||||
onChange: action('changed'),
|
||||
}
|
||||
}}</Story>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../../templates/components/rose/form/select/select';
|
||||
|
||||
/**
|
||||
* This component is used internally by rose/form/select and should not be
|
||||
* instantiated directly.
|
||||
*/
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -1,22 +1,12 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/form/textarea';
|
||||
import ComponentAutoId from '../../../mixins/component-auto-id';
|
||||
|
||||
/**
|
||||
* A `<textarea>` element essentially identical to `Rose::Form::Input` except
|
||||
* for the field element.
|
||||
*
|
||||
* @example
|
||||
* <Rose::Form::Textarea
|
||||
* @id="fieldId"
|
||||
* @value="Text"
|
||||
* @label="Label"
|
||||
* @helperText="Helper text"
|
||||
* @error={{true}}
|
||||
* disabled={{true}}
|
||||
* readonly={{true}}
|
||||
* />
|
||||
*/
|
||||
export default Component.extend({
|
||||
export default Component.extend(ComponentAutoId, {
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -15,20 +15,20 @@ Renders a simple form textarea.
|
||||
@label="Description"
|
||||
@helperText="Enter a description"
|
||||
@error={{false}}
|
||||
disabled={{false}}
|
||||
@disabled={{false}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic" height="10rem">{{
|
||||
<Story name="Basic Textarea" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Textarea
|
||||
@value={{value}}
|
||||
@label={{label}}
|
||||
@helperText={{helperText}}
|
||||
@error={{error}}
|
||||
disabled={{disabled}}
|
||||
@error={{false}}
|
||||
@disabled={{disabled}}
|
||||
readonly={{read-only}}
|
||||
/>
|
||||
`,
|
||||
@@ -38,7 +38,32 @@ Renders a simple form textarea.
|
||||
helperText: text('helperText', 'Helper text'),
|
||||
disabled: boolean('disabled', false),
|
||||
'read-only': boolean('readonly', false),
|
||||
error: boolean('error', false),
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview>
|
||||
<Story name="Textarea with Errors" height="10rem">{{
|
||||
template: hbs`
|
||||
<Rose::Form::Textarea
|
||||
@value={{value}}
|
||||
@label={{label}}
|
||||
@helperText={{helperText}}
|
||||
@error={{true}}
|
||||
@disabled={{disabled}}
|
||||
readonly={{read-only}}
|
||||
as |field|>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Textarea>
|
||||
`,
|
||||
context: {
|
||||
value: text('value', 'Value'),
|
||||
label: text('label', 'Label'),
|
||||
helperText: text('helperText', 'Helper text'),
|
||||
disabled: boolean('disabled', false),
|
||||
'read-only': boolean('readonly', false),
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
@@ -0,0 +1,38 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../templates/components/rose/notification';
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
/**
|
||||
* An accessible alert notification component that displays an icon,
|
||||
* a heading, and optional block content. Notifications may be static or
|
||||
* dismissible. To make a notification dismissible, pass in a
|
||||
* `@dismiss` function.
|
||||
*/
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
|
||||
/**
|
||||
* Returns an icon name based on the notification style.
|
||||
* @type {string}
|
||||
*/
|
||||
@computed('style')
|
||||
get icon() {
|
||||
let icon = 'info-circle-fill';
|
||||
|
||||
switch(this.style) {
|
||||
case 'failure':
|
||||
icon = 'cancel-square-fill';
|
||||
break;
|
||||
case 'success':
|
||||
icon = 'check-circle-fill';
|
||||
break;
|
||||
case 'warning':
|
||||
icon = 'alert-triangle';
|
||||
break;
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
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|Notification" component="Notification" />
|
||||
|
||||
# Notification
|
||||
|
||||
Notifications come in four semantic styles: `info` (default), `success`,
|
||||
`warning`, and `failure`. Heading text is required. Additional block content
|
||||
is optional.
|
||||
|
||||
Notifications may be made dismissible by passing a `@dismiss` function into
|
||||
the component. Dismissible notifications _must_ also have `@dismissText`.
|
||||
This component does not handle dismissal though. Be sure your `@dismiss`
|
||||
handler takes appropriate action and hides the notification.
|
||||
|
||||
```htmlbars
|
||||
<Rose::Notification
|
||||
@style="info"
|
||||
@heading="Alert Notification"
|
||||
@dismiss={{dismissHandler}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
An error occurred.
|
||||
</Rose::Notification>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Notification">{{
|
||||
template: hbs`
|
||||
<Rose::Notification
|
||||
@style="info"
|
||||
@heading="Notification without dismissal"
|
||||
>
|
||||
Some useful information.
|
||||
</Rose::Notification>
|
||||
`,
|
||||
context: {}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Notifications with Dismissal" height="30rem">{{
|
||||
template: hbs`
|
||||
<Rose::Notification
|
||||
@style="info"
|
||||
@heading="Dismissible Notification"
|
||||
@dismiss={{dismiss}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
Some useful information.
|
||||
</Rose::Notification>
|
||||
<Rose::Notification
|
||||
@style="success"
|
||||
@heading="Success"
|
||||
@dismiss={{dismiss}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
Good job!
|
||||
</Rose::Notification>
|
||||
<Rose::Notification
|
||||
@style="warning"
|
||||
@heading="Warning"
|
||||
@dismiss={{dismiss}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
Careful now.
|
||||
</Rose::Notification>
|
||||
<Rose::Notification
|
||||
@style="failure"
|
||||
@heading="Error"
|
||||
@dismiss={{dismiss}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
An error occurred.
|
||||
</Rose::Notification>
|
||||
`,
|
||||
context: {
|
||||
dismiss: action('dismiss'),
|
||||
}
|
||||
}}</Story>
|
||||
</Preview>
|
||||
@@ -0,0 +1,15 @@
|
||||
import Mixin from '@ember/object/mixin';
|
||||
import { v1 } from 'ember-uuid';
|
||||
|
||||
/**
|
||||
* Add this mixin to components for an auto-generated ID.
|
||||
*/
|
||||
export default Mixin.create({
|
||||
/**
|
||||
* Generates an ID for this component and assigns it to `this.id`.
|
||||
*/
|
||||
init() {
|
||||
this.id = `component-${v1()}`;
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
@@ -2,3 +2,4 @@
|
||||
@import 'form';
|
||||
@import 'header';
|
||||
@import 'layout';
|
||||
@import 'notification';
|
||||
@@ -0,0 +1,105 @@
|
||||
@use '../variables/sizing';
|
||||
@use '../utilities/type';
|
||||
|
||||
.rose-notification {
|
||||
$s: sizing.rems(s); // 12
|
||||
$xs: sizing.rems(xs); // 8
|
||||
$xxs: sizing.rems(xxs); // 4
|
||||
$xxxs: sizing.rems(xxxs); // 2
|
||||
$xxxxs: sizing.rems(xxxxs); // 1
|
||||
|
||||
position: relative;
|
||||
padding: sizing.rems(m);
|
||||
margin-bottom: sizing.rems(m);
|
||||
border: sizing.rems(xxxxs) solid;
|
||||
border-radius: $xxxs;
|
||||
box-shadow: 0 $xs $s rgba(var(--stark-components), var(--opacity-3)),
|
||||
0 $xxs $xxs rgba(var(--stark-components), var(--opacity-4));
|
||||
|
||||
.rose-notification-icon {
|
||||
position: relative;
|
||||
top: $xxxxs;
|
||||
}
|
||||
|
||||
.rose-notification-header {
|
||||
@include type.type(m, semibold);
|
||||
}
|
||||
|
||||
.rose-notification-body {
|
||||
@include type.type(s);
|
||||
// hack alert, because the icons are still hard to work with
|
||||
margin-left: sizing.rems(m) + $xxs;
|
||||
}
|
||||
|
||||
.rose-notification-dismiss {
|
||||
position: absolute;
|
||||
color: currentColor;
|
||||
background-color: transparent;
|
||||
border-radius: $xxxs;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
top: sizing.rems(s);
|
||||
right: sizing.rems(s);
|
||||
|
||||
.rose-icon {
|
||||
display: block;
|
||||
padding: $xxs;
|
||||
}
|
||||
|
||||
.rose-notification-dismiss-text {
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
left: -1000px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(var(--stark-components), var(--opacity-3))
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: rgba(var(--stark-components), var(--opacity-2))
|
||||
}
|
||||
}
|
||||
|
||||
--icon-color: var(--info);
|
||||
--header-color: var(--info-starker-1);
|
||||
--border-color: var(--info-subtler-1);
|
||||
--background-color: var(--info-subtler-3);
|
||||
|
||||
border-color: var(--border-color);
|
||||
background-color: var(--background-color);
|
||||
|
||||
.rose-notification-icon {
|
||||
color: var(--icon-color);
|
||||
}
|
||||
|
||||
.rose-notification-header {
|
||||
color: var(--header-color);
|
||||
}
|
||||
|
||||
&.is-failure {
|
||||
--icon-color: var(--failure);
|
||||
--header-color: var(--failure);
|
||||
--border-color: var(--failure-subtler-1);
|
||||
--background-color: var(--failure-subtler-2);
|
||||
}
|
||||
|
||||
&.is-success {
|
||||
--icon-color: var(--success);
|
||||
--header-color: var(--success-starker-1);
|
||||
--border-color: var(--success-subtler-1);
|
||||
--background-color: var(--success-subtler-2);
|
||||
}
|
||||
|
||||
&.is-warning {
|
||||
--icon-color: var(--warning);
|
||||
--header-color: var(--warning-starker-1);
|
||||
--border-color: var(--warning-subtler-1);
|
||||
--background-color: var(--warning-subtler-2);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,11 @@
|
||||
margin-bottom: sizing.rems(xs);
|
||||
color: var(--ui-gray);
|
||||
|
||||
.rose-form-errors {
|
||||
margin-top: sizing.rems(xs);
|
||||
margin-bottom: sizing.rems(xs);
|
||||
}
|
||||
|
||||
.rose-form-checkbox-label {
|
||||
// label styles
|
||||
@include type.type(s, semibold);
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
@import 'checkbox';
|
||||
@import 'select';
|
||||
@import 'radio';
|
||||
@import 'errors';
|
||||
@@ -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);
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
.rose-form-input-field {
|
||||
@include type.type(m);
|
||||
margin-bottom: sizing.rems(xs);
|
||||
padding: sizing.rems(xs);
|
||||
color: var(--stark);
|
||||
background-color: var(--subtle);
|
||||
|
||||
@@ -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);
|
||||
@@ -24,6 +24,7 @@
|
||||
appearance: none;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
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);
|
||||
border-radius: sizing.rems(xxxs);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
@use '../../../variables/sizing';
|
||||
|
||||
@import 'message';
|
||||
|
||||
.rose-form-errors {
|
||||
margin-bottom: sizing.rems(l);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
@use '../../../variables/sizing';
|
||||
@use '../../../utilities/type';
|
||||
|
||||
.rose-form-error-message {
|
||||
@include type.type(xs);
|
||||
color: var(--failure);
|
||||
margin-bottom: sizing.rems(xs);
|
||||
}
|
||||
@@ -4,18 +4,25 @@
|
||||
|
||||
@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 {
|
||||
.rose-button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&.has-icon-left .rose-icon:first-child {
|
||||
margin-left: -(sizing.rems(xs));
|
||||
margin-right: sizing.rems(xxs);
|
||||
}
|
||||
|
||||
&.has-icon-right > .rose-icon:last-child {
|
||||
&.has-icon-right .rose-icon:last-child {
|
||||
margin-left: sizing.rems(xxs);
|
||||
margin-right: -(sizing.rems(xs));
|
||||
}
|
||||
|
||||
@@ -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}}
|
||||
<Rose::Icon
|
||||
@name={{@iconLeft}}
|
||||
@size="medium"
|
||||
/>
|
||||
{{/if}}
|
||||
<span class="rose-button-wrapper">
|
||||
{{#if @iconLeft}}
|
||||
<Rose::Icon
|
||||
@name={{@iconLeft}}
|
||||
@size="medium"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<span class="rose-button-body">
|
||||
{{yield}}
|
||||
<span class="rose-button-body">
|
||||
{{yield}}
|
||||
</span>
|
||||
|
||||
{{#if @iconOnly}}
|
||||
<Rose::Icon
|
||||
@name={{@iconOnly}}
|
||||
@size="medium"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if @iconRight}}
|
||||
<Rose::Icon
|
||||
@name={{@iconRight}}
|
||||
@size="medium"
|
||||
/>
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
{{#if @iconOnly}}
|
||||
<Rose::Icon
|
||||
@name={{@iconOnly}}
|
||||
@size="medium"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if @iconRight}}
|
||||
<Rose::Icon
|
||||
@name={{@iconRight}}
|
||||
@size="medium"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
</button>
|
||||
@@ -0,0 +1,16 @@
|
||||
<form
|
||||
...attributes
|
||||
novalidate
|
||||
method="post"
|
||||
class="rose-form"
|
||||
{{on "submit" this.handleSubmit}}
|
||||
>
|
||||
{{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)
|
||||
)}}
|
||||
</form>
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="rose-form-actions" ...attributes>
|
||||
<Rose::Button
|
||||
@disabled={{@disabled}}
|
||||
@submit={{true}}
|
||||
@style="primary"
|
||||
>
|
||||
{{@submitText}}
|
||||
</Rose::Button>
|
||||
|
||||
{{#if this.showCancel}}
|
||||
<Rose::Button
|
||||
@disabled={{@disabled}}
|
||||
@style="secondary"
|
||||
{{on "click" @cancel}}
|
||||
>
|
||||
{{@cancelText}}
|
||||
</Rose::Button>
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -3,14 +3,18 @@
|
||||
<Input
|
||||
...attributes
|
||||
class="rose-form-checkbox-field"
|
||||
id={{@id}}
|
||||
id={{this.id}}
|
||||
disabled={{@disabled}}
|
||||
@type="checkbox"
|
||||
@checked={{if @checked true false}} />
|
||||
@checked={{if @checked true false}}
|
||||
aria-describedby="{{if @error (concat 'errors-' this.id)}}" />
|
||||
|
||||
<label class="rose-form-checkbox-label" for={{@id}}>
|
||||
<label class="rose-form-checkbox-label" for={{this.id}}>
|
||||
{{@label}}
|
||||
</label>
|
||||
|
||||
{{yield}}
|
||||
{{yield (hash
|
||||
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
|
||||
)}}
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="rose-form-errors" id={{@id}} ...attributes>
|
||||
{{yield (hash
|
||||
message=(component 'rose/form/errors/message')
|
||||
)}}
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
<p class="rose-form-error-message" ...attributes>
|
||||
<Rose::Icon @name="cancel-square-fill" @size="medium" />
|
||||
{{yield}}
|
||||
</p>
|
||||
@@ -1,20 +1,28 @@
|
||||
<div class="rose-form-input{{if @error " error"}}">
|
||||
|
||||
<label class="rose-form-input-label" for={{@id}}>
|
||||
<label class="rose-form-input-label" for={{this.id}}>
|
||||
{{@label}}
|
||||
</label>
|
||||
|
||||
{{#if @helperText}}
|
||||
<span class="rose-form-input-helper-text">{{@helperText}}</span>
|
||||
<span
|
||||
class="rose-form-input-helper-text"
|
||||
id="helper-text-{{this.id}}">
|
||||
{{@helperText}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<Input
|
||||
...attributes
|
||||
class="rose-form-input-field"
|
||||
id={{@id}}
|
||||
id={{this.id}}
|
||||
disabled={{@disabled}}
|
||||
@type={{@type}}
|
||||
@value={{@value}} />
|
||||
@value={{@value}}
|
||||
aria-describedby="{{if @helperText (concat 'helper-text-' this.id)}} {{if @error (concat 'errors-' this.id)}}" />
|
||||
|
||||
{{yield}}
|
||||
{{yield (hash
|
||||
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
|
||||
)}}
|
||||
|
||||
</div>
|
||||
@@ -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)
|
||||
)}}
|
||||
@@ -3,14 +3,15 @@
|
||||
<RadioButton
|
||||
...attributes
|
||||
@radioClass="rose-form-radio-field"
|
||||
@radioId={{@id}}
|
||||
@radioId={{this.id}}
|
||||
type="radio"
|
||||
disabled={{@disabled}}
|
||||
@name={{@name}}
|
||||
@value={{@value}}
|
||||
@groupValue={{@selectedValue}}
|
||||
@disabled={{@disabled}}/>
|
||||
|
||||
<label class="rose-form-radio-label" for={{@id}}>
|
||||
<label class="rose-form-radio-label" for={{this.id}}>
|
||||
{{@label}}
|
||||
</label>
|
||||
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
<div class="rose-form-select{{if @error " error"}}">
|
||||
|
||||
<label class="rose-form-select-label" for={{@id}}>
|
||||
<label class="rose-form-select-label" for={{this.id}}>
|
||||
{{@label}}
|
||||
</label>
|
||||
|
||||
{{#if @helperText}}
|
||||
<span class="rose-form-select-helper-text">{{@helperText}}</span>
|
||||
<span
|
||||
class="rose-form-select-helper-text"
|
||||
id="helper-text-{{this.id}}">
|
||||
{{@helperText}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<XSelect
|
||||
...attributes
|
||||
class="rose-form-select-field"
|
||||
id={{@id}}
|
||||
@value={{@value}}
|
||||
@onChange={{@onChange}}
|
||||
as |xs|
|
||||
>
|
||||
{{yield xs}}
|
||||
</XSelect>
|
||||
{{yield (hash
|
||||
field=(component 'rose/form/select/select'
|
||||
id=this.id
|
||||
name=@name
|
||||
disabled=@disabled
|
||||
value=@value
|
||||
onChange=@onChange
|
||||
helperText=@helperText
|
||||
error=@error
|
||||
)
|
||||
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
|
||||
)}}
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<XSelect
|
||||
class="rose-form-select-field"
|
||||
id={{@id}}
|
||||
name={{@name}}
|
||||
disabled={{@disabled}}
|
||||
@value={{@value}}
|
||||
@onChange={{@onChange}}
|
||||
aria-describedby="{{if @helperText (concat 'helper-text-' this.id)}} {{if @error (concat 'errors-' this.id)}}"
|
||||
as |xs|
|
||||
>
|
||||
{{yield xs}}
|
||||
</XSelect>
|
||||
@@ -1,19 +1,27 @@
|
||||
<div class="rose-form-input{{if @error " error"}}">
|
||||
|
||||
<label class="rose-form-input-label" for={{@id}}>
|
||||
<label class="rose-form-input-label" for={{this.id}}>
|
||||
{{@label}}
|
||||
</label>
|
||||
|
||||
{{#if @helperText}}
|
||||
<span class="rose-form-input-helper-text">{{@helperText}}</span>
|
||||
<span
|
||||
class="rose-form-input-helper-text"
|
||||
id="helper-text-{{this.id}}">
|
||||
{{@helperText}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<Textarea
|
||||
...attributes
|
||||
id={{@id}}
|
||||
class="rose-form-input-field"
|
||||
@value={{@value}} />
|
||||
id={{this.id}}
|
||||
disabled={{@disabled}}
|
||||
@value={{@value}}
|
||||
aria-describedby="{{if @helperText (concat 'helper-text-' this.id)}} {{if @error (concat 'errors-' this.id)}}" />
|
||||
|
||||
{{yield}}
|
||||
{{yield (hash
|
||||
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
|
||||
)}}
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
<section
|
||||
...attributes
|
||||
class="rose-notification is-{{@style}}{{if @dismiss " is-dismissible"}}"
|
||||
role="alert"
|
||||
aria-live="{{if @dismiss "assertive"}}"
|
||||
aria-atomic="true"
|
||||
>
|
||||
|
||||
<header class="rose-notification-header">
|
||||
<Rose::Icon
|
||||
class="rose-notification-icon"
|
||||
@name={{this.icon}}
|
||||
@size="medium" />
|
||||
{{@heading}}
|
||||
</header>
|
||||
|
||||
<div class="rose-notification-body">
|
||||
{{yield}}
|
||||
</div>
|
||||
|
||||
{{#if @dismiss}}
|
||||
<button
|
||||
type="button"
|
||||
class="rose-notification-dismiss"
|
||||
title={{@dismissText}}
|
||||
{{on "click" @dismiss}}
|
||||
>
|
||||
<Rose::Icon
|
||||
@name="cancel-plain"
|
||||
@size="medium" />
|
||||
<span class="rose-notification-dismiss-text">
|
||||
{{@dismissText}}
|
||||
</span>
|
||||
</button>
|
||||
{{/if}}
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/form';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/form/actions';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/form/errors';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/form/errors/message';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/form/select/select';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/notification';
|
||||
@@ -64,6 +64,7 @@
|
||||
"ember-source": "~3.12.0",
|
||||
"ember-source-channel-url": "^2.0.1",
|
||||
"ember-try": "^1.4.0",
|
||||
"ember-uuid": "^2.1.0",
|
||||
"emberx-select": "github:adopted-ember-addons/emberx-select#bc5f774",
|
||||
"eslint-plugin-ember": "^7.7.2",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
|
||||
@@ -2,9 +2,11 @@ import Controller from '@ember/controller';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class IndexController extends Controller {
|
||||
color = 'green';
|
||||
|
||||
@action
|
||||
selectChange(/*value*/) {
|
||||
actionHandler(/*value*/) {
|
||||
// eslint-disable-next-line no-console
|
||||
//console.log(value);
|
||||
//console.log('action handled');
|
||||
}
|
||||
}
|
||||
@@ -1,205 +1,183 @@
|
||||
<Rose::Layout::Page as |page|>
|
||||
<page.header>
|
||||
<Rose::Header as |header|>
|
||||
<header.brand @logo="logo" @text="Product Name" />
|
||||
<Rose::Header as |header|>
|
||||
|
||||
<header.nav as |nav|>
|
||||
<nav.dropdown @text="org-name" as |dropdown|>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</nav.dropdown>
|
||||
<nav.link @route="index">Section</nav.link>
|
||||
<nav.link @route="about">Section</nav.link>
|
||||
</header.nav>
|
||||
<header.brand @logo="logo" @text="Product Name" />
|
||||
|
||||
<header.nav as |nav|>
|
||||
<nav.dropdown @text="org-name" as |dropdown|>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</nav.dropdown>
|
||||
<nav.link @route="index">Section</nav.link>
|
||||
<nav.link @route="about">Section</nav.link>
|
||||
</header.nav>
|
||||
|
||||
|
||||
<header.utilities as |utilities|>
|
||||
<utilities.dropdown
|
||||
@text="user@example.net"
|
||||
@iconOnly={{true}}
|
||||
@icon="user-square-fill" as |dropdown|
|
||||
>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</utilities.dropdown>
|
||||
</header.utilities>
|
||||
|
||||
</Rose::Header>
|
||||
</page.header>
|
||||
<page.sidebar />
|
||||
<page.main>
|
||||
Dummy app index template
|
||||
|
||||
<h2>Icon</h2>
|
||||
<Rose::Icon @name="alert-circle-fill" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="medium" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="small" />
|
||||
|
||||
<h2>Button</h2>
|
||||
<Rose::Button @style="primary">Primary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="primary" @disabled={{true}}>Primary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<Rose::Button @style="secondary">Secondary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="secondary" @disabled={{true}}>Secondary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<h2>Form</h2>
|
||||
<Rose::Form::Select
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.selectChange}}
|
||||
as |select|
|
||||
<header.utilities as |utilities|>
|
||||
<utilities.dropdown
|
||||
@text="user@example.net"
|
||||
@iconOnly={{true}}
|
||||
@icon="user-square-fill" as |dropdown|
|
||||
>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</utilities.dropdown>
|
||||
</header.utilities>
|
||||
|
||||
</Rose::Header>
|
||||
|
||||
|
||||
Dummy app index template
|
||||
|
||||
<Rose::Notification
|
||||
@style="failure"
|
||||
@heading="Error"
|
||||
@dismiss={{this.actionHandler}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
An error occurred.
|
||||
</Rose::Notification>
|
||||
|
||||
<h2>Icon</h2>
|
||||
<Rose::Icon @name="alert-circle-fill" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="medium" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="small" />
|
||||
|
||||
<h2>Button</h2>
|
||||
<Rose::Button @style="primary">Primary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="primary" @disabled={{true}}>Primary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<Rose::Button @style="secondary">Secondary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="secondary" @disabled={{true}}>Secondary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<h2>Form</h2>
|
||||
<Rose::Form
|
||||
@onSubmit={{this.actionHandler}}
|
||||
@cancel={{this.actionHandler}}
|
||||
@disabled={{false}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h3>Textareas</h3>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h3>Selects</h3>
|
||||
<form.select
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.actionHandler}}
|
||||
as |field|
|
||||
>
|
||||
<field.field 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>
|
||||
</field.field>
|
||||
</form.select>
|
||||
<form.select
|
||||
|
||||
<Rose::Form::Select
|
||||
disabled={{true}}
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.selectChange}}
|
||||
as |select|
|
||||
>
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.actionHandler}}
|
||||
as |field|
|
||||
>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
</Rose::Form::Select>
|
||||
|
||||
<Rose::Form::Input
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
|
||||
<Rose::Form::Input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
|
||||
<Rose::Form::Input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
|
||||
<Rose::Form::Input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
</field.field>
|
||||
</form.select>
|
||||
|
||||
|
||||
<Rose::Form::Textarea
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
|
||||
<Rose::Form::Textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
|
||||
<Rose::Form::Textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
|
||||
<Rose::Form::Textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h2>Checkbox</h2>
|
||||
<Rose::Form::Checkbox
|
||||
@id="checkbox-1"
|
||||
@label="Label"
|
||||
/>
|
||||
<Rose::Form::Checkbox
|
||||
@id="checkbox-2"
|
||||
@error={{true}}
|
||||
@label="Error"
|
||||
/>
|
||||
<Rose::Form::Checkbox
|
||||
@id="checkbox-3"
|
||||
@checked={{true}}
|
||||
@label="Checked"
|
||||
/>
|
||||
<Rose::Form::Checkbox
|
||||
@id="checkbox-4"
|
||||
@label="Disabled"
|
||||
disabled={{true}}
|
||||
/>
|
||||
<Rose::Form::Checkbox
|
||||
@id="checkbox-5"
|
||||
@checked={{true}}
|
||||
@label="Disabled + Checked"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h2>Radio field</h2>
|
||||
<Rose::Form::Radio::Radio
|
||||
@id="radio-1"
|
||||
@label="Label"
|
||||
@value="radio-1"
|
||||
/>
|
||||
<Rose::Form::Radio::Radio
|
||||
@id="radio-2"
|
||||
@error={{true}}
|
||||
@label="Error"
|
||||
@value="radio-2"
|
||||
/>
|
||||
<Rose::Form::Radio::Radio
|
||||
@id="radio-3"
|
||||
@label="Checked"
|
||||
/>
|
||||
|
||||
<Rose::Form::Radio::Radio
|
||||
@id="radio-4"
|
||||
@label="Disabled"
|
||||
<h3>Radio Group</h3>
|
||||
<form.radioGroup @name="color" @selectedValue={{this.color}} as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@label="Red"
|
||||
@value="red"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Green"
|
||||
@value="green"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Blue"
|
||||
@value="blue"
|
||||
@disabled={{true}}
|
||||
@value="radio-4"
|
||||
/>
|
||||
<Rose::Form::Radio::Radio
|
||||
@id="radio-5"
|
||||
@label="Disabled + Checked"
|
||||
@value="radio-5"
|
||||
@variable="radio-5"
|
||||
@disabled={{true}}
|
||||
/>
|
||||
/>
|
||||
</form.radioGroup>
|
||||
|
||||
<h2>Radio field group</h2>
|
||||
<Rose::Form::Radio::Group @name="color" @variable="green" as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@id="red-radio"
|
||||
@label="Red"
|
||||
@value="red"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="green-radio"
|
||||
@label="Green"
|
||||
@value="green"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="blue-radio"
|
||||
@label="Blue"
|
||||
@value="blue"
|
||||
/>
|
||||
</Rose::Form::Radio::Group>
|
||||
<h3>Checkboxes</h3>
|
||||
<form.checkbox
|
||||
@label="Label"
|
||||
/>
|
||||
<form.checkbox
|
||||
@error={{true}}
|
||||
@label="Error"
|
||||
/>
|
||||
<form.checkbox
|
||||
@checked={{true}}
|
||||
@label="Checked"
|
||||
/>
|
||||
<form.checkbox
|
||||
@label="Disabled"
|
||||
disabled={{true}}
|
||||
/>
|
||||
<form.checkbox
|
||||
@checked={{true}}
|
||||
@label="Disabled + Checked"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
</page.main>
|
||||
</Rose::Layout::Page>
|
||||
<form.actions
|
||||
@submitText="Save"
|
||||
@cancelText="Cancel" />
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,67 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render, find, click } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
module('Integration | Component | rose/form', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders and handles submit/cancel actions', async function (assert) {
|
||||
assert.expect(3);
|
||||
this.submit = () => assert.ok(true, 'submitted');
|
||||
this.cancel = () => assert.ok(true, 'cancelled');
|
||||
await render(hbs`
|
||||
<Rose::Form
|
||||
@onSubmit={{this.submit}}
|
||||
@cancel={{this.cancel}}
|
||||
@disabled={{false}}
|
||||
as |form|
|
||||
>
|
||||
<form.actions
|
||||
@submitText="Save"
|
||||
@cancelText="Cancel" />
|
||||
</Rose::Form>
|
||||
`);
|
||||
assert.ok(find('.rose-form'));
|
||||
await click('[type="submit"]');
|
||||
await click('button:not([type="submit"])');
|
||||
});
|
||||
|
||||
test('it can render contextual form components', async function (assert) {
|
||||
assert.expect(5);
|
||||
this.submit = () => {};
|
||||
this.cancel = () => {};
|
||||
this.select = () => {};
|
||||
await render(hbs`
|
||||
<Rose::Form
|
||||
@onSubmit={{this.submit}}
|
||||
@cancel={{this.cancel}}
|
||||
@disabled={{false}}
|
||||
as |form|
|
||||
>
|
||||
<form.input @label="Input" name="input-field" />
|
||||
<form.textarea @label="Textarea" name="textarea-field" />
|
||||
<form.select
|
||||
@label="Select"
|
||||
@name="select-field"
|
||||
@onChange={{this.select}}
|
||||
as |field|
|
||||
>
|
||||
<field.field />
|
||||
</form.select>
|
||||
<form.checkbox @label="Checkbox" name="checkbox-field" />
|
||||
<form.radioGroup @name="radio-group-field" @selectedValue="green" as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@label="Red"
|
||||
@value="red"
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</Rose::Form>
|
||||
`);
|
||||
assert.ok(find('[name="input-field"]'));
|
||||
assert.ok(find('[name="textarea-field"]'));
|
||||
assert.ok(find('[name="select-field"]'));
|
||||
assert.ok(find('[name="checkbox-field"]'));
|
||||
assert.ok(find('[name="radio-group-field"]'));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render, find, click } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
module('Integration | Component | rose/form/actions', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders a submit button and a regular button', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.cancel = () => {};
|
||||
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"])');
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,23 @@ module('Integration | Component | rose/form/checkbox', function (hooks) {
|
||||
assert.ok(await find('input'));
|
||||
});
|
||||
|
||||
test('it displays optional errors', async function (assert) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Checkbox @error={{true}} as |field|>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Checkbox>
|
||||
`);
|
||||
const fieldEl = find('input');
|
||||
const id = fieldEl.id;
|
||||
const errorsId = `errors-${id}`;
|
||||
const errorMessageEl = find('.rose-form-errors');
|
||||
assert.equal(errorMessageEl.id, errorsId);
|
||||
assert.equal(errorMessageEl.textContent.trim(), 'An error occurred.');
|
||||
assert.equal(fieldEl.getAttribute('aria-describedby').trim(), errorsId);
|
||||
});
|
||||
|
||||
test('it is not checked by default', async function (assert) {
|
||||
await render(hbs`<Rose::Form::Checkbox />`);
|
||||
assert.equal(await find('input').checked, false);
|
||||
@@ -32,8 +49,8 @@ module('Integration | Component | rose/form/checkbox', function (hooks) {
|
||||
assert.ok(await find('.error'));
|
||||
});
|
||||
|
||||
test('it is disabled when disabled={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Form::Checkbox disabled={{true}} />`);
|
||||
test('it is disabled when @disabled={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Form::Checkbox @disabled={{true}} />`);
|
||||
assert.equal(await find('input').disabled, true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
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/form/errors', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
assert.expect(3);
|
||||
await render(hbs`
|
||||
<Rose::Form::Errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
<errors.message>Another error occurred.</errors.message>
|
||||
<//Rose::Form::Errors>
|
||||
`);
|
||||
assert.ok(find('.rose-form-errors'));
|
||||
assert.equal(
|
||||
find('.rose-form-error-message:first-child').textContent.trim(),
|
||||
'An error occurred.'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-form-error-message:last-child').textContent.trim(),
|
||||
'Another error occurred.'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
module('Integration | Component | rose/form/errors/message', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Errors::Message>
|
||||
An error occurred.
|
||||
</Rose::Form::Errors::Message>
|
||||
`);
|
||||
assert.equal(this.element.textContent.trim(), 'An error occurred.');
|
||||
});
|
||||
});
|
||||
@@ -14,9 +14,32 @@ module('Integration | Component | rose/form/input', function (hooks) {
|
||||
|
||||
test('it displays optional helper text', async function (assert) {
|
||||
await render(hbs`<Rose::Form::Input @helperText="Help me" />`);
|
||||
const fieldEl = find('input');
|
||||
const id = fieldEl.id;
|
||||
const helperId = `helper-text-${id}`;
|
||||
const helperTextEl = find('.rose-form-input-helper-text');
|
||||
assert.equal(helperTextEl.textContent.trim(), 'Help me');
|
||||
assert.equal(helperTextEl.id, helperId);
|
||||
assert.equal(fieldEl.getAttribute('aria-describedby').trim(), helperId);
|
||||
});
|
||||
|
||||
test('it displays optional errors', async function (assert) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Input @error={{true}} as |field|>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Input>
|
||||
`);
|
||||
const fieldEl = find('input');
|
||||
const id = fieldEl.id;
|
||||
const errorsId = `errors-${id}`;
|
||||
const errorMessageEl = find('.rose-form-errors');
|
||||
assert.equal(errorMessageEl.id, errorsId);
|
||||
assert.equal(errorMessageEl.textContent.trim(), 'An error occurred.');
|
||||
assert.equal(
|
||||
await find('.rose-form-input-helper-text').textContent.trim(),
|
||||
'Help me'
|
||||
fieldEl.getAttribute('aria-describedby').split(' ')[1],
|
||||
errorsId
|
||||
);
|
||||
});
|
||||
|
||||
@@ -31,7 +54,7 @@ module('Integration | Component | rose/form/input', function (hooks) {
|
||||
});
|
||||
|
||||
test('it supports disabled attribute', async function (assert) {
|
||||
await render(hbs`<Rose::Form::Input disabled={{true}} />`);
|
||||
await render(hbs`<Rose::Form::Input @disabled={{true}} />`);
|
||||
assert.ok(await find('[disabled]'));
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render, click, find, findAll } from '@ember/test-helpers';
|
||||
import { render, click, findAll } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
module('Integration | Component | rose/form/radio/group', function (hooks) {
|
||||
@@ -10,12 +10,12 @@ module('Integration | Component | rose/form/radio/group', function (hooks) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Radio::Group @name="bird" as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@id="bird-1"
|
||||
@name="bird"
|
||||
@label="Pegion"
|
||||
@value="pegion"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="bird-2"
|
||||
@name="bird"
|
||||
@label="flamingo"
|
||||
@value="flamingo"
|
||||
/>
|
||||
@@ -31,37 +31,37 @@ module('Integration | Component | rose/form/radio/group', function (hooks) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Radio::Group @name="bird" @selectedValue="flamingo" as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@id="bird-1"
|
||||
@name="bird"
|
||||
@label="Pegion"
|
||||
@value="pegion"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="bird-2"
|
||||
@name="bird"
|
||||
@label="flamingo"
|
||||
@value="flamingo"
|
||||
/>
|
||||
</Rose::Form::Radio::Group>
|
||||
`);
|
||||
|
||||
assert.equal(find('#bird-1').checked, false);
|
||||
assert.equal(find('#bird-2').checked, true);
|
||||
assert.equal(findAll('[type="radio"]')[0].checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[1].checked, true);
|
||||
|
||||
await click(find('#bird-1'));
|
||||
await click(findAll('[type="radio"]')[0]);
|
||||
|
||||
assert.equal(find('#bird-1').checked, true);
|
||||
assert.equal(find('#bird-2').checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[0].checked, true);
|
||||
assert.equal(findAll('[type="radio"]')[1].checked, false);
|
||||
});
|
||||
|
||||
test('it reflects active radiofield value in @selectedValue', async function (assert) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Radio::Group @name="bird" @selectedValue={{this.selectedValue}} as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@id="bird-1"
|
||||
@name="bird"
|
||||
@label="Pegion"
|
||||
@value="pegion"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="bird-2"
|
||||
@name="bird"
|
||||
@label="flamingo"
|
||||
@value="flamingo"
|
||||
/>
|
||||
@@ -70,10 +70,10 @@ module('Integration | Component | rose/form/radio/group', function (hooks) {
|
||||
|
||||
assert.notOk(this.selectedValue);
|
||||
|
||||
await click(find('#bird-1'));
|
||||
await click(findAll('[type="radio"]')[0]);
|
||||
assert.equal(this.selectedValue, 'pegion');
|
||||
|
||||
await click(find('#bird-2'));
|
||||
await click(findAll('[type="radio"]')[1]);
|
||||
assert.equal(this.selectedValue, 'flamingo');
|
||||
});
|
||||
|
||||
@@ -82,31 +82,31 @@ module('Integration | Component | rose/form/radio/group', function (hooks) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Radio::Group @name="bird" @selectedValue={{this.selectedValue}} as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@id="bird-1"
|
||||
@name="bird"
|
||||
@label="Pegion"
|
||||
@value="pegion"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@id="bird-2"
|
||||
@name="bird"
|
||||
@label="flamingo"
|
||||
@value="flamingo"
|
||||
/>
|
||||
</Rose::Form::Radio::Group>
|
||||
`);
|
||||
|
||||
assert.equal(find('#bird-1').checked, false);
|
||||
assert.equal(find('#bird-2').checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[0].checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[1].checked, false);
|
||||
|
||||
this.set('selectedValue', 'flamingo');
|
||||
assert.equal(find('#bird-1').checked, false);
|
||||
assert.equal(find('#bird-2').checked, true);
|
||||
assert.equal(findAll('[type="radio"]')[0].checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[1].checked, true);
|
||||
|
||||
this.set('selectedValue', 'pegion');
|
||||
assert.equal(find('#bird-1').checked, true);
|
||||
assert.equal(find('#bird-2').checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[0].checked, true);
|
||||
assert.equal(findAll('[type="radio"]')[1].checked, false);
|
||||
|
||||
this.set('selectedValue', 'dog');
|
||||
assert.equal(find('#bird-1').checked, false);
|
||||
assert.equal(find('#bird-2').checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[0].checked, false);
|
||||
assert.equal(findAll('[type="radio"]')[1].checked, false);
|
||||
});
|
||||
});
|
||||
@@ -12,12 +12,14 @@ module('Integration | Component | rose/form/select', function (hooks) {
|
||||
<Rose::Form::Select
|
||||
@label="Label"
|
||||
@onChange={{fn this.onChange}}
|
||||
as |select|
|
||||
as |field|
|
||||
>
|
||||
<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>
|
||||
<field.field 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>
|
||||
</field.field>
|
||||
</Rose::Form::Select>
|
||||
`);
|
||||
assert.equal(find('label').textContent.trim(), 'Label');
|
||||
@@ -30,16 +32,51 @@ module('Integration | Component | rose/form/select', function (hooks) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Select
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@helperText="Help me"
|
||||
@onChange={{fn this.onChange}}
|
||||
as |select|
|
||||
as |field|
|
||||
>
|
||||
<select.option>Choose an option</select.option>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
</field.field>
|
||||
</Rose::Form::Select>
|
||||
`);
|
||||
const fieldEl = find('select');
|
||||
const id = fieldEl.id;
|
||||
const helperId = `helper-text-${id}`;
|
||||
const helperTextEl = find('.rose-form-select-helper-text');
|
||||
assert.equal(helperTextEl.textContent.trim(), 'Help me');
|
||||
assert.equal(helperTextEl.id, helperId);
|
||||
assert.equal(fieldEl.getAttribute('aria-describedby').trim(), helperId);
|
||||
});
|
||||
|
||||
test('it displays optional errors', async function (assert) {
|
||||
this.onChange = () => {};
|
||||
await render(hbs`
|
||||
<Rose::Form::Select
|
||||
@label="Label"
|
||||
@helperText="Help me"
|
||||
@onChange={{fn this.onChange}}
|
||||
@error={{true}}
|
||||
as |field|
|
||||
>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
</field.field>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Select>
|
||||
`);
|
||||
const fieldEl = find('select');
|
||||
const id = fieldEl.id;
|
||||
const errorsId = `errors-${id}`;
|
||||
const errorMessageEl = find('.rose-form-errors');
|
||||
assert.equal(errorMessageEl.id, errorsId);
|
||||
assert.equal(errorMessageEl.textContent.trim(), 'An error occurred.');
|
||||
assert.equal(
|
||||
find('.rose-form-select-helper-text').textContent.trim(),
|
||||
'Helper text'
|
||||
fieldEl.getAttribute('aria-describedby').split(' ')[1],
|
||||
errorsId
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,10 +85,12 @@ module('Integration | Component | rose/form/select', function (hooks) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Select
|
||||
@onChange={{fn this.onChange}}
|
||||
disabled={{true}}
|
||||
as |select|
|
||||
@disabled={{true}}
|
||||
as |field|
|
||||
>
|
||||
<select.option>Choose an option</select.option>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
</field.field>
|
||||
</Rose::Form::Select>
|
||||
`);
|
||||
assert.ok(find('[disabled]'));
|
||||
@@ -64,10 +103,12 @@ module('Integration | Component | rose/form/select', function (hooks) {
|
||||
<Rose::Form::Select
|
||||
@onChange={{fn this.onChange}}
|
||||
@value={{value}}
|
||||
as |select|
|
||||
as |field|
|
||||
>
|
||||
<select.option @value="value-1">value-1</select.option>
|
||||
<select.option @value="value-2">value-2</select.option>
|
||||
<field.field as |select|>
|
||||
<select.option @value="value-1">value-1</select.option>
|
||||
<select.option @value="value-2">value-2</select.option>
|
||||
</field.field>
|
||||
</Rose::Form::Select>
|
||||
`);
|
||||
assert.equal(find('select').value, 'value-1');
|
||||
@@ -91,12 +132,14 @@ module('Integration | Component | rose/form/select', function (hooks) {
|
||||
this.onChange = this.onChange1;
|
||||
await render(hbs`
|
||||
<Rose::Form::Select
|
||||
name="my-select"
|
||||
@name="my-select"
|
||||
@onChange={{fn this.onChange}}
|
||||
as |select|
|
||||
as |field|
|
||||
>
|
||||
<select.option>Choose an option</select.option>
|
||||
<select.option @value="value-1">value-1</select.option>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
<select.option @value="value-1">value-1</select.option>
|
||||
</field.field>
|
||||
</Rose::Form::Select>
|
||||
`);
|
||||
await fillIn('[name="my-select"]', 'value-1');
|
||||
|
||||
@@ -14,14 +14,37 @@ module('Integration | Component | rose/form/textarea', function (hooks) {
|
||||
|
||||
test('it displays optional helper text', async function (assert) {
|
||||
await render(hbs`<Rose::Form::Textarea @helperText="Help me" />`);
|
||||
const fieldEl = find('textarea');
|
||||
const id = fieldEl.id;
|
||||
const helperId = `helper-text-${id}`;
|
||||
const helperTextEl = find('.rose-form-input-helper-text');
|
||||
assert.equal(helperTextEl.textContent.trim(), 'Help me');
|
||||
assert.equal(helperTextEl.id, helperId);
|
||||
assert.equal(fieldEl.getAttribute('aria-describedby').trim(), helperId);
|
||||
});
|
||||
|
||||
test('it displays optional errors', async function (assert) {
|
||||
await render(hbs`
|
||||
<Rose::Form::Textarea @error={{true}} as |field|>
|
||||
<field.errors as |errors|>
|
||||
<errors.message>An error occurred.</errors.message>
|
||||
</field.errors>
|
||||
</Rose::Form::Textarea>
|
||||
`);
|
||||
const fieldEl = find('textarea');
|
||||
const id = fieldEl.id;
|
||||
const errorsId = `errors-${id}`;
|
||||
const errorMessageEl = find('.rose-form-errors');
|
||||
assert.equal(errorMessageEl.id, errorsId);
|
||||
assert.equal(errorMessageEl.textContent.trim(), 'An error occurred.');
|
||||
assert.equal(
|
||||
await find('.rose-form-input-helper-text').textContent.trim(),
|
||||
'Help me'
|
||||
fieldEl.getAttribute('aria-describedby').split(' ')[1],
|
||||
errorsId
|
||||
);
|
||||
});
|
||||
|
||||
test('it supports disabled attribute', async function (assert) {
|
||||
await render(hbs`<Rose::Form::Textarea disabled={{true}} />`);
|
||||
await render(hbs`<Rose::Form::Textarea @disabled={{true}} />`);
|
||||
assert.ok(await find('[disabled]'));
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render, find, click } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
module('Integration | Component | rose/notification', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
await render(hbs`
|
||||
<Rose::Notification
|
||||
@style="info"
|
||||
@heading="Alert Notification"
|
||||
>
|
||||
An error occurred.
|
||||
</Rose::Notification>
|
||||
`);
|
||||
assert.ok(find('.rose-notification'));
|
||||
assert.equal(find('.rose-notification-body').textContent.trim(), 'An error occurred.');
|
||||
});
|
||||
|
||||
test('it has optional dismiss button which triggers a function', async function(assert) {
|
||||
assert.expect(1);
|
||||
this.dismiss = () => assert.ok(true, 'dismiss clicked');
|
||||
await render(hbs`
|
||||
<Rose::Notification
|
||||
@style="info"
|
||||
@heading="Alert Notification"
|
||||
@dismiss={{this.dismiss}} />
|
||||
`);
|
||||
await click('.rose-notification-dismiss');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import EmberObject from '@ember/object';
|
||||
import ComponentAutoIdMixin from 'rose/mixins/component-auto-id';
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
module('Unit | Mixin | component-auto-id', function () {
|
||||
test('it generates an ID and assigns it to the object', function (assert) {
|
||||
let ComponentAutoIdObject = EmberObject.extend(ComponentAutoIdMixin);
|
||||
let subject = ComponentAutoIdObject.create();
|
||||
assert.ok(subject.id);
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,6 @@
|
||||
{{on "submit" @submit}}>
|
||||
|
||||
<Rose::Form::Input
|
||||
@id="name"
|
||||
name="name"
|
||||
@type="name"
|
||||
@value={{@model.name}}
|
||||
@@ -16,7 +15,6 @@
|
||||
/>
|
||||
|
||||
<Rose::Form::Textarea
|
||||
@id="description"
|
||||
name="description"
|
||||
@type="description"
|
||||
@value={{@model.description}}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"format:sass": "prettier --write app/**/*.scss",
|
||||
"start": "ember serve",
|
||||
"clean:coverage": "rm -rf coverage_*",
|
||||
"pretest": "yarn clean:coverage && yarn lint",
|
||||
"pretest": "yarn clean:coverage",
|
||||
"test": "COVERAGE=true ember exam --random",
|
||||
"posttest": "ember coverage-merge && yarn clean:coverage"
|
||||
},
|
||||
@@ -65,6 +65,7 @@
|
||||
"ember-resolver": "^7.0.0",
|
||||
"ember-route-action-helper": "^2.0.8",
|
||||
"ember-source": "~3.16.0",
|
||||
"ember-uuid": "^2.1.0",
|
||||
"ember-welcome-page": "^4.0.0",
|
||||
"emberx-select": "github:adopted-ember-addons/emberx-select#bc5f774",
|
||||
"eslint-plugin-ember": "^7.7.2",
|
||||
|
||||
@@ -8002,6 +8002,14 @@ ember-try@^1.4.0:
|
||||
rsvp "^4.7.0"
|
||||
walk-sync "^1.1.3"
|
||||
|
||||
ember-uuid@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-uuid/-/ember-uuid-2.1.0.tgz#a65d030534d47ced1ea22be9b7d3821eff71f99c"
|
||||
integrity sha512-oiUNIBPCyJtzkcRUAi3qCRwU+yq5r9gzlPLKRG1pQ2WA209lphmZQRR+TyaeNwOijs9bjttzFV6YOyaTO40B/A==
|
||||
dependencies:
|
||||
ember-cli-babel "^7.11.1"
|
||||
ember-cli-htmlbars "^4.0.0"
|
||||
|
||||
ember-welcome-page@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-welcome-page/-/ember-welcome-page-4.0.0.tgz#14f5ef8b477f9480c39548d3ebd51f5c4ffb0a14"
|
||||
|
||||
Reference in new issue
Block a user