Add radio field rose component
This commit is contained in:
8 files changed
+276
No files matched your search
@@ -0,0 +1,20 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/form/radio';
|
||||
|
||||
/**
|
||||
* A HTML `<input type="radio">` element.
|
||||
*
|
||||
* @example
|
||||
* <Rose::Form::Radio
|
||||
* @id="fieldId"
|
||||
* @label="label"
|
||||
* name="fieldName"
|
||||
* disabled={{true}}
|
||||
* @checked={{true}}
|
||||
* @error={{true}}
|
||||
* />
|
||||
*/
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
@import 'input';
|
||||
@import 'checkbox';
|
||||
@import 'select';
|
||||
@import 'radio';
|
||||
@@ -0,0 +1,131 @@
|
||||
@use '../../variables/sizing';
|
||||
@use '../../utilities/type';
|
||||
|
||||
$radio-svg: (
|
||||
'default': "<svg viewBox='0 0 24 24' fill='%23aaaaaa' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' /></svg>",
|
||||
|
||||
'hover': "<svg viewBox='0 0 24 24' fill='%236f7682' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' /></svg>",
|
||||
|
||||
'focus': "<svg viewBox='0 0 24 24' fill='%231563ff' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' /></svg>",
|
||||
|
||||
'checked': "<svg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' fill='%231563ff'/></svg>",
|
||||
|
||||
'disabled': "<svg viewBox='0 0 24 24' fill='%23bac1cc' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' /></svg>",
|
||||
|
||||
'disabled-checked': "<svg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' fill='%23bac1cc'/></svg>",
|
||||
|
||||
'error': "<svg viewBox='0 0 24 24' fill='%23c73445' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' /></svg>",
|
||||
|
||||
'error-checked': "<svg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' fill='%23c73445'/></svg>",
|
||||
);
|
||||
|
||||
$data-svg-prefix: 'data:image/svg+xml;utf-8,';
|
||||
|
||||
.rose-form-radio {
|
||||
position: relative;
|
||||
margin-bottom: sizing.rems(xs);
|
||||
color: var(--ui-gray);
|
||||
|
||||
.rose-form-radio-label {
|
||||
@include type.type(s, semibold);
|
||||
color: currentColor;
|
||||
padding-left: sizing.rems(l);
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
display: block;
|
||||
width: sizing.rems(m);
|
||||
height: sizing.rems(m);
|
||||
pointer-events: none;
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: -#{sizing.rems(xxs)};
|
||||
left: -#{sizing.rems(xxxs) + sizing.rems(xxxxs)};
|
||||
display: block;
|
||||
width: sizing.rems(l);
|
||||
height: sizing.rems(l);
|
||||
transform: scale(2);
|
||||
pointer-events: none;
|
||||
content: ' ';
|
||||
background: no-repeat 50%/50% 50%;
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'default'));
|
||||
}
|
||||
}
|
||||
|
||||
.rose-form-radio-field {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
width: sizing.rems(m);
|
||||
height: sizing.rems(m);
|
||||
opacity: 0;
|
||||
|
||||
&:not(:disabled) {
|
||||
&:hover {
|
||||
~ .rose-form-radio-label {
|
||||
&::after {
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'hover'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
~ .rose-form-radio-label {
|
||||
&::after {
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'focus'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
~ .rose-form-radio-label {
|
||||
&::after {
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'checked'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
~ .rose-form-radio-label {
|
||||
&::after {
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'disabled'));
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
~ .rose-form-radio-label {
|
||||
&::after {
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'disabled-checked'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: var(--failure);
|
||||
|
||||
.rose-form-radio-field {
|
||||
&:not(:disabled):not(:focus) {
|
||||
~ .rose-form-radio-label {
|
||||
&::after {
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'error'));
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
~ .rose-form-radio-label {
|
||||
&::after {
|
||||
background-image: url($data-svg-prefix + map-get($radio-svg, 'error-checked'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<div class="rose-form-radio{{if @error " error"}}">
|
||||
|
||||
<input
|
||||
...attributes
|
||||
class="rose-form-radio-field"
|
||||
id={{@id}}
|
||||
type="radio"
|
||||
checked={{@checked}} />
|
||||
|
||||
<label class="rose-form-radio-label" for={{@id}}>
|
||||
{{@label}}
|
||||
</label>
|
||||
|
||||
{{yield}}
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/form/radio';
|
||||
@@ -118,3 +118,34 @@ Dummy app index template
|
||||
@label="Disabled + Checked"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h2>Radio</h2>
|
||||
<Rose::Form::Radio
|
||||
@id="radio-1"
|
||||
@label="Label"
|
||||
name="radio-group"
|
||||
/>
|
||||
<Rose::Form::Radio
|
||||
@id="radio-2"
|
||||
@error={{true}}
|
||||
@label="Error"
|
||||
name="radio-group"
|
||||
/>
|
||||
<Rose::Form::Radio
|
||||
@id="radio-3"
|
||||
@checked={{true}}
|
||||
@label="Checked"
|
||||
name="radio-group"
|
||||
/>
|
||||
|
||||
<Rose::Form::Radio
|
||||
@id="radio-4"
|
||||
@label="Disabled"
|
||||
disabled={{true}}
|
||||
/>
|
||||
<Rose::Form::Radio
|
||||
@id="radio-5"
|
||||
@checked={{true}}
|
||||
@label="Disabled + Checked"
|
||||
disabled={{true}}
|
||||
/>
|
||||
@@ -0,0 +1,27 @@
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import { text, boolean } from '@storybook/addon-knobs';
|
||||
|
||||
export default {
|
||||
title: 'Rose::Form::Radio',
|
||||
};
|
||||
|
||||
export const Normal = () => ({
|
||||
template: hbs`
|
||||
<Rose::Form::Radio
|
||||
@id={{id}}
|
||||
name={{name}}
|
||||
@label={{label}}
|
||||
@checked={{checked}}
|
||||
@error={{error}}
|
||||
disabled={{disabled}}
|
||||
/>
|
||||
`,
|
||||
context: {
|
||||
label: text('text', 'Radiofield'),
|
||||
id: text('id', 'radio-1'),
|
||||
name: text('name', 'radio-1'),
|
||||
checked: boolean('checked', false),
|
||||
error: boolean('error', false),
|
||||
disabled: boolean('disabled', false),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
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/radio', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio />`);
|
||||
assert.ok(await find('input'));
|
||||
assert.equal(await find('input').type, 'radio');
|
||||
});
|
||||
|
||||
test('it renders with label', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio @label="Label"/>`);
|
||||
assert.equal(await find('label').textContent.trim(), 'Label');
|
||||
});
|
||||
|
||||
test('it is not checked by default', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio />`);
|
||||
assert.equal(await find('input').checked, false);
|
||||
});
|
||||
|
||||
test('it is not disabled by default', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio />`);
|
||||
assert.equal(await find('input').disabled, false);
|
||||
});
|
||||
|
||||
test('it is not in error state by default', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio />`);
|
||||
assert.notOk(await find('.error'));
|
||||
});
|
||||
|
||||
test('it is checked when @checked={{true}}', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio @checked={{true}}/>`);
|
||||
assert.equal(await find('input').checked, true);
|
||||
});
|
||||
|
||||
test('it is disabled when disabled={{true}}', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio disabled={{true}}/>`);
|
||||
assert.equal(await find('input').disabled, true);
|
||||
});
|
||||
|
||||
test('it is in error state when @error={{true}}', async function(assert) {
|
||||
await render(hbs`<Rose::Form::Radio @error={{true}} />`);
|
||||
assert.ok(await find('.error'));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user