diff --git a/src/atoms/blockquote/Blockquote.css b/src/atoms/blockquote/Blockquote.css index 00c348255..cd57f7fe5 100644 --- a/src/atoms/blockquote/Blockquote.css +++ b/src/atoms/blockquote/Blockquote.css @@ -1,6 +1,6 @@ .a-blockquote { @apply my-2; @apply py-2 pr-2 pl-4; - @apply border-l-4 border-solid border-light; + @apply border-l-4 border-solid border-gray-300; @apply leading-relaxed; } diff --git a/src/molecules/input/Input.html b/src/molecules/input/Input.html new file mode 100644 index 000000000..a2b9d65c1 --- /dev/null +++ b/src/molecules/input/Input.html @@ -0,0 +1,21 @@ +
+ + + + {{ label }} + + + + + +
diff --git a/src/molecules/input/Input.js b/src/molecules/input/Input.js new file mode 100644 index 000000000..394199da2 --- /dev/null +++ b/src/molecules/input/Input.js @@ -0,0 +1,68 @@ +// @vue/component +import getClass from '../../../utils/helpers/get-class.js' + +export default { + mixins: [getClass], + inheritAttrs: false, + props: { + /** + * Prop to handle v-model + */ + value: { + type: String, + default: null + }, + /** + * Input id + */ + id: { + type: String, + required: true + }, + /** + * Label text + */ + label: { + type: String, + default: null + } + }, + computed: { + listeners () { + return { + ...this.$listeners, + input: event => this.$emit('input', event.target.value) + } + } + }, + data () { + return { + config: { + base: { + input: [ + 'relative' + ], + input__field: [ + 'w-full', 'h-12', + 'px-4' + ] + }, + primary: { + input__field: [ + 'border', 'border-solid', 'border-form', + 'placeholder-primary' + ] + }, + inline: { + input: [ + 'flex', 'items-center' + ], + input__label: [ + 'flex-shrink-0', + 'm-4', 'mb-4' + ] + } + } + } + } +} diff --git a/src/molecules/input/Input.scss b/src/molecules/input/Input.scss new file mode 100644 index 000000000..c755d3d85 --- /dev/null +++ b/src/molecules/input/Input.scss @@ -0,0 +1,50 @@ +@import '../../../assets/styles/_globals.scss'; + +$input__margin : 0 0 $spacer--medium 0 !default; +$input-wrapper__label-margin : 0 $spacer--medium 0 0 !default; + +$input__field-padding : 0 $spacer--large 0 $spacer--medium !default; +$input__field-width : 100% !default; +$input__field-height : 40px !default; +$input__field-border : 1px solid $form-elements-border-color !default; +$input__field-border-radius : $form-elements-radius !default; +$input__field-placeholder-color: $gray !default; + +$input__icon-top : 20px !default; +$input__icon-right : 8px !default; + +.a-input { + // position: relative; + // margin: $input__margin; + + // &--inline { + // display: flex; + // align-items: center; + + // .a-label { + // flex-shrink: 0; + // margin: $input-wrapper__label-margin; + // } + // } + + // &__field { + // // width: $input__field-width; + // // height: $input__field-height; + // // padding: $input__field-padding; + // // border: $input__field-border; + // // border-radius: $input__field-border-radius; + + // // &[type='search'] { + // // -webkit-appearance: textfield; + + // // &::-webkit-search-decoration, + // // &::-webkit-search-cancel-button { + // // -webkit-appearance: none; + // // } + // // } + + // // &::placeholder { + // // color: $input__field-placeholder-color; + // // } + // } +} diff --git a/src/molecules/input/Input.spec.js b/src/molecules/input/Input.spec.js new file mode 100644 index 000000000..922a5bdcb --- /dev/null +++ b/src/molecules/input/Input.spec.js @@ -0,0 +1,66 @@ +import { mount } from '@vue/test-utils' +import AInput from './Input.vue' + +describe('Input', () => { + it('has default structure', () => { + const wrapper = mount(AInput, { + propsData: { + id: 'input-id' + } + }) + const input = wrapper.find('.a-input__field') + + expect(wrapper.is('div')).toBe(true) + expect(wrapper.classes()).toContain('a-input') + expect(wrapper.classes().length).toBe(1) + + expect(input.is('input')).toBe(true) + expect(input.classes()).toContain('a-input__field') + expect(input.classes().length).toBe(1) + expect(input.attributes().id).toBeDefined() + expect(input.attributes().id).toBe('input-id') + }) + + it('renders email input when type set to email', () => { + const wrapper = mount(AInput, { + propsData: { + id: 'input-id', + type: 'email' + } + }) + + const input = wrapper.find('.a-input__field') + expect(input.attributes('type')).toBe('email') + }) + + it('renders slots content when passed', () => { + const wrapper = mount(AInput, { + propsData: { + id: 'input-id' + }, + slots: { + label: '' + } + }) + + const label = wrapper.find('.a-input > label') + + expect(label.exists()).toBe(true) + expect(label.text()).toEqual('Alpaca UI') + }) + + it('emits an input event', () => { + const wrapper = mount(AInput, { + propsData: { + id: 'input-id' + } + }) + + const textInput = wrapper.find('input') + textInput.setValue('Sample text') + + expect(wrapper.emitted('input')).toBeTruthy() + expect(wrapper.emitted().input[0].length).toBe(1) + expect(wrapper.emitted().input[0][0]).toEqual('Sample text') + }) +}) diff --git a/src/molecules/input/Input.stories.js b/src/molecules/input/Input.stories.js new file mode 100644 index 000000000..cf0890702 --- /dev/null +++ b/src/molecules/input/Input.stories.js @@ -0,0 +1,110 @@ +import AInput from './Input.vue' +import AIcon from '../../atoms/icon/Icon.vue' +import AIconPerson from '../../atoms/icon/templates/IconPerson.vue' + +export default { + title: 'Molecules/Input', + component: AInput, + argTypes: { + type: { + control: { + type: 'text' + } + }, + placeholder: { + control: { + type: 'text' + } + }, + label: { + control: { + type: 'text' + } + } + } +} + +const args = { + type: 'text', + placeholder: 'Placeholder text...', + label: 'Label text' +} + +const Template = (args, { argTypes }) => ({ + components: { AInput }, + props: Object.keys(argTypes), + data: () => { + return { + inputValue: '' + } + }, + template: ` +
+ + + Model: {{ inputValue }} + +
+ ` +}) + +export const Default = Template.bind({}) + +export const Inline = Template.bind({}) + +export const WithSlots = (args, { argTypes }) => ({ + components: { AInput, AIcon, AIconPerson }, + props: Object.keys(argTypes), + data: () => { + return { + inputValue: '', + iconStyles: { + top: '29px', + right: '8px', + cursor: 'pointer' + } + } + }, + template: ` +
+ + + + + Model: {{ inputValue }} + +
+ ` +}) + +Default.args = args +Inline.args = { + ...args, + variant: ['primary', 'inline'] +} +WithSlots.args = args diff --git a/src/molecules/input/Input.vue b/src/molecules/input/Input.vue new file mode 100644 index 000000000..da87a9054 --- /dev/null +++ b/src/molecules/input/Input.vue @@ -0,0 +1,14 @@ +