Merge pull request #907 from hashicorp/feat-create-radio-card-component

Feat: create radio card component
This commit is contained in:
Susmitha Girumala authored and GitHub committed 2022-01-26 10:27:57 -05:00
commit a380bccbf1
7 files changed
+378

No files matched your search

@@ -0,0 +1,7 @@
import RoseFormRadioRadioComponent from '../radio';
export default class RoseFormRadioCardComponent extends RoseFormRadioRadioComponent {
// =attributes
layout = this.args.layout;
className = `rose-form-radio-card ${this.layout}`;
}
@@ -0,0 +1,100 @@
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
import { hbs } from 'ember-cli-htmlbars';
import { text, boolean, select } from '@storybook/addon-knobs';
<Meta title="Rose|Form/Radio/Radio/Card" component="Form/Radio/Radio/Card" />
# Form Radiofield in a wide format
Renders a form radiofield in a Wide format.
```htmlbars
<Rose::Form::Radio::Card
@label="Yes"
@error={{false}}
@value="yes-agree"
@selectedValue="yes-agree"
@disabled={{false}}
@changed={{fn}}
@layout='wide'
/>
```
<Preview>
<Story name="Basic Wide" height="10rem">{{
template: hbs`
<Rose::Form::Radio::Card
@label={{label}}
@error={{error}}
@value={{value}}
@selectedValue={{selectedValue}}
@disabled={{disabled}}
@icon={{icon}}
@helperText={{helperText}}
@layout='wide'
/>
`,
context: {
label: text('text', 'Azure'),
error: boolean('error', false),
value: text('value', 'value and selectedValue must match to select radiofield'),
selectedValue: text(
'selectedValue',
'value and selectedValue must match to select radiofield'
),
helperText: text('helperText', 'Record financial transactions using'),
disabled: boolean('disabled', false),
}
}}</Story>
</Preview>
Renders a form radiofield in a tile format.
```htmlbars
<Rose::Form::Radio::Card
@label="Yes"
@error={{false}}
@value="yes-agree"
@selectedValue="yes-agree"
@disabled={{false}}
@changed={{fn}}
@layout='tile'
/>
```
<Preview>
<Story name="Basic tile" height="10rem">{{
template: hbs`
<Rose::Form::Radio::Card
@label={{label}}
@error={{error}}
@value={{value}}
@selectedValue={{selectedValue}}
@disabled={{disabled}}
@icon={{icon}}
@helperText={{helperText}}
@layout='tile'
/>
`,
context: {
label: text('text', 'Azure'),
error: boolean('error', false),
value: text('value', 'value and selectedValue must match to select radiofield'),
selectedValue: text(
'selectedValue',
'value and selectedValue must match to select radiofield'
),
helperText: text('helperText', 'Record financial transactions using'),
disabled: boolean('disabled', false),
icon: select(
'icon',
{
'none': null,
'flight-icons/svg/azure-color-16': 'flight-icons/svg/azure-color-16',
},
null
),
}
}}</Story>
</Preview>
@@ -22,6 +22,7 @@
{{/if}}
{{@label}}
<span class="radio-card-overlay"></span>
{{#if @helperText}}
<Rose::Form::HelperText @id="helper-text-{{this.id}}" @error={{@error}} @link={{@link}} @linkText={{@linkText}}>
{{@helperText}}
@@ -6,3 +6,4 @@
@import 'select';
@import 'radio';
@import 'fieldset';
@import 'radio-card';
@@ -0,0 +1,215 @@
@use '../../variables/sizing';
@use '../../utilities/type';
@use '../../variables/typography';
$size-xxl: sizing.rems(xxl); //48
$size-xl: sizing.rems(xl); //36
$size-l: sizing.rems(l); // 24
$size-m: sizing.rems(m); // 16
$size-s: sizing.rems(s); //12
$size-xs: sizing.rems(xs); // 8
$size-xxs: sizing.rems(xxs); // 4
$size-xxxs: sizing.rems(xxxs); // 2
$size-xxxxs: sizing.rems(xxxxs); // 1
$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>",
);
.rose-form-radio-card {
$cardWideWidth: $size-m * 11;
$cardTileWidth: $size-m * 7.25;
$borderWidth: $size-xxxs * 2;
&.wide {
width: ($size-m) * 23;
}
&.tile {
width: ($size-m) * 15;
.rose-icon {
--size: #{$size-xl};
padding: $size-xxxs;
}
.rose-form-radio-label {
display: flex;
flex-direction: column;
align-items: center;
height: $size-m * 9;
&::after {
left: $cardTileWidth - $borderWidth;
}
}
}
position: relative;
display: flex;
align-items: center;
justify-content: center;
.radio-card-overlay {
position: absolute;
height: $size-l + $size-xxs;
background-color: var(--ui-gray-subtler-5);
width: 100%;
bottom: 0;
right: 0;
border-bottom-left-radius: $size-xxxs;
border-bottom-right-radius: $size-xxxs;
}
.rose-form-radio-label {
@include type.type(s, bold);
display: flex;
color: var(--black);
width: ($size-m) * 23;
height: ($size-m) * 7.4;
display: block;
position: relative;
text-align: left;
word-break: break-all;
border: $size-xxxxs solid var(--ui-gray-subtler-6);
box-shadow: 0 $size-xxs $size-xxs
rgba(var(--stark-components), var(--opacity-2));
border-radius: $size-xxs;
padding: $size-s $size-m;
box-sizing: border-box;
background-color: var(--white);
.rose-form-helper-text {
@include type.type(xs, normal);
}
&::after {
position: absolute;
bottom: $size-xxs + $size-xxxxs;
right: $cardWideWidth - $borderWidth;
display: block;
width: $size-m;
height: $size-m;
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;
z-index: 1;
bottom: $size-xs;
opacity: 0;
&:not(:disabled) {
&:focus {
~ .rose-form-radio-label {
&::after {
background-image: url($data-svg-prefix + map-get(
$radio-svg,
'focus'
));
}
}
}
&:hover {
~ .rose-form-radio-label {
border: $size-xxxxs solid var(--ui-gray);
}
}
&:checked {
~ .rose-form-radio-label {
&::after {
background-image: url($data-svg-prefix + map-get(
$radio-svg,
'checked'
));
}
.radio-card-overlay {
background-color: var(--action-subtler-1h);
}
border: $size-xxxxs solid var(--info-subtler-1);
}
}
}
&:disabled {
~ .rose-form-radio-label {
border: $size-xxxxs solid var(--ui-border-subtler-1);
background-color: var(--ui-gray-subtler-6);
color: var(--ui-gray-starker-1);
&::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 {
.rose-form-radio-field {
&:not(:disabled):not(:focus) {
&:not(:disabled):not(:focus) {
~ .rose-form-radio-label {
color: var(--ui-gray);
border: $size-xxxxs solid var(--failure);
.radio-card-overlay {
background-color: var(--failure-subtler-2);
}
.rose-form-helper-text.error {
color: var(--ui-gray);
}
&::after {
background-image: url($data-svg-prefix + map-get(
$radio-svg,
'error'
));
}
}
&:checked {
~ .rose-form-radio-label {
color: var(--ui-gray);
border: $size-xxxxs solid var(--failure);
.radio-card-overlay {
background-color: var(--failure-subtler-2);
}
&::after {
background-image: url($data-svg-prefix + map-get(
$radio-svg,
'error-checked'
));
}
}
}
}
}
}
}
}
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/form/radio/card';
@@ -0,0 +1,53 @@
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/card', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<Rose::Form::Radio::Card />`);
assert.ok(await find('input'));
assert.equal(await find('input').type, 'radio');
});
test('it renders in a tile format when tile layout is applied', async function (assert) {
await render(hbs`<Rose::Form::Radio::Card @layout="tile"/>`);
assert.ok(await find('.tile'));
});
test('it supports an icon', async function (assert) {
await render(
hbs`<Rose::Form::Radio::Card @icon="flight-icons/svg/user-circle-16" />`
);
assert.ok(find('svg'));
});
test('it is checked when @value and @selectedValue values match', async function (assert) {
await render(
hbs`<Rose::Form::Radio::Card @value="tree" @selectedValue="tree"/>`
);
assert.true(await find('input').checked);
});
test('it is not disabled by default', async function (assert) {
await render(hbs`<Rose::Form::Radio::Card />`);
assert.false(await find('input').disabled);
});
test('it is not in error state by default', async function (assert) {
await render(hbs`<Rose::Form::Radio::Card />`);
assert.notOk(await find('.error'));
});
test('it is disabled when @disabled={{true}}', async function (assert) {
await render(hbs`<Rose::Form::Radio::Card @disabled={{true}}/>`);
assert.true(await find('input').disabled);
});
test('it is in error state when @error={{true}}', async function (assert) {
await render(hbs`<Rose::Form::Radio::Card @error={{true}} />`);
assert.ok(await find('.error'));
});
});