diff --git a/src/components/v-notice/index.ts b/src/components/v-notice/index.ts new file mode 100644 index 0000000000..05b7fcbbf0 --- /dev/null +++ b/src/components/v-notice/index.ts @@ -0,0 +1,4 @@ +import VNotice from './v-notice.vue'; + +export { VNotice }; +export default VNotice; diff --git a/src/components/v-notice/v-notice.readme.md b/src/components/v-notice/v-notice.readme.md new file mode 100644 index 0000000000..657a148ec5 --- /dev/null +++ b/src/components/v-notice/v-notice.readme.md @@ -0,0 +1,28 @@ +# Notice + +```html +I'm a notice! +``` + +## Props +| Prop | Description | Default | +|-----------|--------------------------------------------------------------------|---------| +| `success` | Shows the success notice | `false` | +| `warning` | Shows the warning notice | `false` | +| `danger` | Shows the danger notice | `false` | +| `icon` | Custom icon name, or false if you want to hide the icon completely | `null` | + +## Slots +| Slot | Description | Data | +|-----------|-------------|------| +| _default_ | | -- | + +## Events +n/a + +## CSS Variables +| Variable | Default | +|-------------------------------|----------------------------| +| `--v-notice-color` | `var(--foreground-color);` | +| `--v-notice-background-color` | `var(--action-light);` | +| `--v-notice-icon-color` | `var(--action);` | diff --git a/src/components/v-notice/v-notice.story.ts b/src/components/v-notice/v-notice.story.ts new file mode 100644 index 0000000000..23aee2080b --- /dev/null +++ b/src/components/v-notice/v-notice.story.ts @@ -0,0 +1,85 @@ +import { + withKnobs, + text, + boolean, + number, + color, + select, + optionsKnob as options +} from '@storybook/addon-knobs'; +import { action } from '@storybook/addon-actions'; +import Vue from 'vue'; +import VNotice from './v-notice.vue'; +import VIcon from '../v-icon/'; +import markdown from './v-notice.readme.md'; +import withPadding from '../../../.storybook/decorators/with-padding'; + +Vue.component('v-notice', VNotice); +Vue.component('v-icon', VIcon); + +export default { + title: 'Components / Notice', + component: VNotice, + decorators: [withKnobs, withPadding], + parameters: { + notes: markdown + } +}; + +export const withText = () => ({ + props: { + text: { + default: text('Text', 'This is a notice') + }, + success: { + default: boolean('Success', false) + }, + warning: { + default: boolean('Warning', false) + }, + danger: { + default: boolean('Danger', false) + } + }, + template: `{{text}}` +}); + +export const withCustomColors = () => ({ + props: { + color: { + default: text('Color', 'red') + }, + backgroundColor: { + default: text('Background Color', 'papayawhip') + }, + iconColor: { + default: text('Icon Color', 'blue') + } + }, + template: ` + This is a notice + ` +}); + +export const withCustomIcon = () => ({ + props: { + icon: { + default: text('Icon', 'translate') + } + }, + template: ` + This is a notice + ` +}); + +export const noIcon = () => ({ + template: ` + This is a notice + ` +}); diff --git a/src/components/v-notice/v-notice.test.ts b/src/components/v-notice/v-notice.test.ts new file mode 100644 index 0000000000..b405d48d73 --- /dev/null +++ b/src/components/v-notice/v-notice.test.ts @@ -0,0 +1,79 @@ +import { mount, createLocalVue, Wrapper } from '@vue/test-utils'; +import VueCompositionAPI from '@vue/composition-api'; +import VNotice from './v-notice.vue'; +import VIcon from '@/components/v-icon/'; + +const localVue = createLocalVue(); +localVue.use(VueCompositionAPI); +localVue.component('v-icon', VIcon); + +describe('Notice', () => { + let component: Wrapper; + + beforeEach(() => { + component = mount(VNotice, { + localVue, + slots: { + default: 'I like pizza' + } + }); + }); + + it('Renders the default slot in the notice', () => { + expect(component.text()).toContain('I like pizza'); + }); + + it('Uses the right color / icon combo for success', async () => { + component.setProps({ + success: true + }); + + await component.vm.$nextTick(); + + expect(component.classes()).toContain('success'); + expect((component.vm as any).iconName).toBe('check_circle'); + }); + + it('Uses the right color / icon combo for warning', async () => { + component.setProps({ + warning: true + }); + + await component.vm.$nextTick(); + + expect(component.classes()).toContain('warning'); + expect((component.vm as any).iconName).toBe('warning'); + }); + + it('Uses the right color / icon combo for danger', async () => { + component.setProps({ + danger: true + }); + + await component.vm.$nextTick(); + + expect(component.classes()).toContain('danger'); + expect((component.vm as any).iconName).toBe('error'); + }); + + it('Defaults to success if all props are given', async () => { + component.setProps({ + success: true, + warning: true, + danger: true + }); + + await component.vm.$nextTick(); + + expect((component.vm as any).iconName).toBe('check_circle'); + expect(component.classes()).toContain('success'); + }); + + it('Allows setting a custom icon', async () => { + component.setProps({ + icon: 'person' + }); + await component.vm.$nextTick(); + expect((component.vm as any).iconName).toBe('person'); + }); +}); diff --git a/src/components/v-notice/v-notice.vue b/src/components/v-notice/v-notice.vue new file mode 100644 index 0000000000..9b55a66b5e --- /dev/null +++ b/src/components/v-notice/v-notice.vue @@ -0,0 +1,98 @@ + + + + +