style: 💄 add button component with styles, tests, and story
This commit is contained in:
12 files changed
+242
-23
No files matched your search
@@ -0,0 +1,13 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../templates/components/rose/button';
|
||||
|
||||
/**
|
||||
* A simple HTML `<button>` element.
|
||||
*
|
||||
* @example
|
||||
* <Rose::Button @submit={{true}} @style="primary">Save</Rose::Button>
|
||||
* <Rose::Button @disabled={{true}} @style="secondary">Disabled</Rose::Button>
|
||||
*/
|
||||
export default Component.extend({
|
||||
layout,
|
||||
});
|
||||
@@ -1,6 +1,3 @@
|
||||
@import 'reset';
|
||||
@import 'variables';
|
||||
|
||||
html {
|
||||
background: pink;
|
||||
}
|
||||
@import 'components';
|
||||
@@ -0,0 +1,56 @@
|
||||
@use '../utilities/button';
|
||||
|
||||
@include button.button-style(
|
||||
'primary',
|
||||
(
|
||||
color: var(--white),
|
||||
background-color: var(--info),
|
||||
border-color: var(--info-starker-2),
|
||||
box-shadow: 0px 4px 4px rgba(var(--stark-components), var(--opacity-2)),
|
||||
text-shadow: 0px 1px 1px rgba(var(--black-components), var(--opacity-2)),
|
||||
),
|
||||
(
|
||||
background-color: var(--info-subtler-1),
|
||||
box-shadow: (
|
||||
0px 4px 4px rgba(var(--stark-components), var(--opacity-3)),
|
||||
0px 4px 8px rgba(var(--stark-components), var(--opacity-4)),
|
||||
),
|
||||
),
|
||||
(
|
||||
background-color: var(--info-starker-1),
|
||||
box-shadow: none,
|
||||
),
|
||||
(
|
||||
opacity: var(--opacity-1),
|
||||
box-shadow: none,
|
||||
)
|
||||
);
|
||||
|
||||
@include button.button-style(
|
||||
'secondary',
|
||||
(
|
||||
color: var(--ui-gray-starker-3),
|
||||
background-color: var(--ui-gray-subtler-5),
|
||||
border-color: var(--ui-gray-subtler-2),
|
||||
box-shadow: 0px 4px 4px rgba(var(--stark-components), var(--opacity-2)),
|
||||
),
|
||||
(
|
||||
color: var(--ui-gray-starker-4),
|
||||
background-color: var(--subtle),
|
||||
border-color: var(--ui-gray-starker-1),
|
||||
box-shadow: (
|
||||
0px 4px 4px rgba(var(--stark-components), var(--opacity-3)),
|
||||
0px 4px 8px rgba(var(--stark-components), var(--opacity-4)),
|
||||
),
|
||||
),
|
||||
(
|
||||
color: var(--ui-gray-starker-4),
|
||||
background-color: var(--ui-gray-subtler-3),
|
||||
border-color: var(--ui-gray-starker-1),
|
||||
box-shadow: none,
|
||||
),
|
||||
(
|
||||
opacity: var(--opacity-1),
|
||||
box-shadow: none,
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
@import 'button';
|
||||
@@ -0,0 +1,80 @@
|
||||
@use 'sass:map';
|
||||
|
||||
@mixin button {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 5px 24px;
|
||||
line-height: 1.846; // targeting 24px
|
||||
border-radius: 2px;
|
||||
border: 1px solid;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@mixin button-style($name, $default, $hover: &, $active: &, $disabled: &) {
|
||||
.rose-button-#{$name} {
|
||||
@include button;
|
||||
border-color: map.get($default, border-color);
|
||||
color: map.get($default, color);
|
||||
background-color: map.get($default, background-color);
|
||||
@if map.get($default, 'box-shadow') {
|
||||
box-shadow: map.get($default, 'box-shadow');
|
||||
}
|
||||
@if map.get($default, 'text-shadow') {
|
||||
text-shadow: map.get($default, 'text-shadow');
|
||||
}
|
||||
|
||||
&:not(:disabled) {
|
||||
@if $hover {
|
||||
&:hover {
|
||||
@if map.get($hover, 'border-color') {
|
||||
border-color: map.get($hover, 'border-color');
|
||||
}
|
||||
@if map.get($hover, 'color') {
|
||||
color: map.get($hover, 'color');
|
||||
}
|
||||
@if map.get($hover, 'background-color') {
|
||||
background-color: map.get($hover, 'background-color');
|
||||
}
|
||||
@if map.get($hover, 'box-shadow') {
|
||||
box-shadow: map.get($hover, 'box-shadow');
|
||||
}
|
||||
@if map.get($hover, 'text-shadow') {
|
||||
text-shadow: map.get($hover, 'text-shadow');
|
||||
}
|
||||
}
|
||||
}
|
||||
@if $active {
|
||||
&:active {
|
||||
@if map.get($active, 'border-color') {
|
||||
border-color: map.get($active, 'border-color');
|
||||
}
|
||||
@if map.get($active, 'color') {
|
||||
color: map.get($active, 'color');
|
||||
}
|
||||
@if map.get($active, 'background-color') {
|
||||
background-color: map.get($active, 'background-color');
|
||||
}
|
||||
@if map.get($active, 'box-shadow') {
|
||||
box-shadow: map.get($active, 'box-shadow');
|
||||
}
|
||||
@if map.get($active, 'text-shadow') {
|
||||
text-shadow: map.get($active, 'text-shadow');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if $disabled {
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
@if map.get($disabled, 'opacity') {
|
||||
opacity: map.get($disabled, 'opacity');
|
||||
}
|
||||
@if map.get($disabled, 'box-shadow') {
|
||||
box-shadow: map.get($disabled, 'box-shadow');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
@forward 'button';
|
||||
@@ -0,0 +1,8 @@
|
||||
<button
|
||||
...attributes
|
||||
type={{if @submit "submit" "button"}}
|
||||
disabled={{if @disabled "disabled"}}
|
||||
class={{if @style (concat "rose-button-" @style)}}
|
||||
>
|
||||
{{yield}}
|
||||
</button>
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/button';
|
||||
@@ -1 +1,11 @@
|
||||
Dummy app index template
|
||||
|
||||
<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>
|
||||
@@ -1,19 +0,0 @@
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { text /*withKnobs, boolean, select */ } from '@storybook/addon-knobs';
|
||||
|
||||
export default {
|
||||
title: 'Button',
|
||||
};
|
||||
|
||||
export const Normal = () => ({
|
||||
template: hbs`
|
||||
<button {{action onClick}}>
|
||||
{{text}}
|
||||
</button>
|
||||
`,
|
||||
context: {
|
||||
text: text('text', 'Button Text'),
|
||||
onClick: action('clicked'),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { text, boolean, select } from '@storybook/addon-knobs';
|
||||
|
||||
export default {
|
||||
title: 'Rose::Button',
|
||||
};
|
||||
|
||||
export const Normal = () => ({
|
||||
template: hbs`
|
||||
<Rose::Button
|
||||
@submit={{submit}}
|
||||
@disabled={{disabled}}
|
||||
@style={{style}}
|
||||
{{action onClick}}
|
||||
>
|
||||
{{text}}
|
||||
</Rose::Button>
|
||||
`,
|
||||
context: {
|
||||
text: text('text', 'Button 🌈'),
|
||||
submit: boolean('submit', false),
|
||||
disabled: boolean('disabled', false),
|
||||
style: select(
|
||||
'style',
|
||||
{
|
||||
primary: 'primary',
|
||||
secondary: 'secondary',
|
||||
warning: 'warning',
|
||||
ghost: 'ghost',
|
||||
},
|
||||
'primary'
|
||||
),
|
||||
onClick: action('clicked'),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
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/button', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
await render(hbs`<Rose::Button>Button 🌈</Rose::Button>`);
|
||||
assert.equal(this.element.textContent.trim(), 'Button 🌈');
|
||||
});
|
||||
|
||||
test('it is type="button" by default', async function (assert) {
|
||||
await render(hbs`<Rose::Button>Button</Rose::Button>`);
|
||||
assert.equal(await find('button').type, 'button');
|
||||
});
|
||||
|
||||
test('it is type="submit" when @submit={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Button @submit={{true}} />`);
|
||||
assert.equal(await find('button').type, 'submit');
|
||||
});
|
||||
|
||||
test('it is disabled when @disabled={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Button @disabled={{true}} />`);
|
||||
assert.equal(await find('button').disabled, true);
|
||||
});
|
||||
|
||||
test('it adds a style class', async function (assert) {
|
||||
await render(hbs`<Rose::Button @style="primary" />`);
|
||||
assert.ok(await find('button.rose-button-primary'));
|
||||
await render(hbs`<Rose::Button @style="secondary" />`);
|
||||
assert.ok(await find('button.rose-button-secondary'));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user