Skip to content
This repository has been archived by the owner on Nov 30, 2020. It is now read-only.

Commit

Permalink
feat(text-field): add text field icon (#317)
Browse files Browse the repository at this point in the history
* feat(text-field): add text field icon

* feat(text-field): add text field icon

* feat(text-field): add text-field-icon

* test(text-field): update snapshots
  • Loading branch information
tychenjiajun authored Jul 1, 2019
1 parent 0650e3d commit 8f271f1
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 29 deletions.
25 changes: 0 additions & 25 deletions components/text-field/TextField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -131,38 +131,13 @@ export default {
}
},
mounted () {
this.updateSlots()
this.slotObserver = new MutationObserver(() => this.updateSlots())
this.slotObserver.observe(this.$el, {
childList: true,
subtree: true
})
this.mdcTextField = MDCTextField.attachTo(this.$el)
this.mdcTextField.useNativeValidation = this.useNativeValidation
this.mdcTextField.valid = this.valid
this.mdcTextField.disabled = this.disabled
},
beforeDestroy () {
this.slotObserver.disconnect()
this.mdcTextField.destroy()
},
methods: {
updateSlots () {
if (this.$slots.leadingIcon) {
this.$slots.leadingIcon.map(n => {
n.elm.classList.add('mdc-text-field__icon')
n.elm.setAttribute('tabindex', '0')
n.elm.setAttribute('role', 'button')
})
}
if (this.$slots.trailingIcon) {
this.$slots.trailingIcon.map(n => {
n.elm.classList.add('mdc-text-field__icon')
n.elm.setAttribute('tabindex', '0')
n.elm.setAttribute('role', 'button')
})
}
}
}
}
</script>
52 changes: 52 additions & 0 deletions components/text-field/TextFieldIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<template>
<i
class="mdc-text-field__icon"
v-bind="attrs"
v-on="$listeners"
tabindex="0"
role="button"
>
<slot />
</i>
</template>

<script>
import { MDCTextFieldIcon } from '@material/textfield/icon'
export default {
name: 'TextFieldIcon',
props: {
clickable: {
type: Boolean,
default: true
}
},
data () {
return {
attrs: Object.assign({}, this.$attrs),
mdcTextFieldIcon: undefined
}
},
watch: {
clickable () {
if (this.clickable) {
this.$set(this.attrs, 'tabindex', '0')
this.$set(this.attrs, 'role', 'button')
} else {
this.$delete(this.attrs, 'tabindex')
this.$delete(this.attrs, 'role')
}
}
},
mounted () {
if (this.clickable) {
this.$set(this.attrs, 'tabindex', '0')
this.$set(this.attrs, 'role', 'button')
}
this.mdcTextFieldIcon = MDCTextFieldIcon.attachTo(this.$el)
},
beforeDestroy () {
this.mdcTextFieldIcon.destroyed()
}
}
</script>
105 changes: 105 additions & 0 deletions components/text-field/__test__/TextField.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import 'mutationobserver-shim'
import { mount } from '@vue/test-utils'
import TextField from '../TextField.vue'
import TextFieldCharacterCounter from '../TextFieldCharacterCounter.vue'
import TextFieldIcon from '../TextFieldIcon.vue'
import TextFIeldHelperText from '../TextFieldHelperText.vue'

describe('Text Field', () => {
it('should mount', () => {
let wrapper = mount(TextField)
expect(wrapper.isVueInstance()).toBeTruthy()
expect(wrapper.vm.$data.mdcTextField).toBeDefined()
})

it('should render with no prop', () => {
let wrapper = mount(TextField)
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field')
expect(wrapper.classes()).toContain('mdc-text-field--no-label')
expect(wrapper.find('input').attributes('disabled')).toBeUndefined()
})

it('should render as focused', () => {
let wrapper = mount(TextField)
let input = wrapper.find('input')
input.trigger('focus')
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field--focused')
})

it('should render as disabled', () => {
let wrapper = mount(TextField, {
propsData: {
disabled: true
}
})
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field--disabled')
expect(wrapper.find('input').attributes('disabled')).toBeDefined()
})

it('should render as outlined', () => {
let wrapper = mount(TextField, {
propsData: {
outlined: true
}
})
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field--outlined')
expect(wrapper.find('.mdc-notched-outline').exists()).toBe(true)
})

it('should render as dense', () => {
let wrapper = mount(TextField, {
propsData: {
dense: true
}
})
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field--dense')
})

it('should render as fullWidth', () => {
let wrapper = mount(TextField, {
propsData: {
fullWidth: true
}
})
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field--fullwidth')
})

it('should render and emit', () => {
let wrapper = mount(TextField, {
propsData: {
value: 'val'
}
})

const input = wrapper.find('input')
input.setValue('test')
expect(wrapper.emitted().model.length).toBe(1)
expect(wrapper.emitted().model[0]).toEqual(['test'])
})

it('should render with leading icon', () => {
let wrapper = mount(TextField, {
slots: {
leadingIcon: TextFieldIcon
}
})
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field--with-leading-icon')
})

it('should render with trailing icon', () => {
let wrapper = mount(TextField, {
slots: {
trailingIcon: TextFieldIcon
}
})
expect(wrapper).toMatchSnapshot()
expect(wrapper.classes()).toContain('mdc-text-field--with-trailing-icon')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Text Field should render as dense 1`] = `
<div class="mdc-text-field mdc-text-field--dense mdc-text-field--no-label"> <input class="mdc-text-field__input">
<!---->
<!---->
<!---->
</div>
`;
exports[`Text Field should render as disabled 1`] = `
<div class="mdc-text-field mdc-text-field--no-label mdc-text-field--disabled"> <input class="mdc-text-field__input" disabled="">
<!---->
<!---->
<!---->
</div>
`;
exports[`Text Field should render as focused 1`] = `
<div class="mdc-text-field mdc-text-field--no-label mdc-text-field--focused"> <input class="mdc-text-field__input">
<!---->
<!---->
<!---->
</div>
`;
exports[`Text Field should render as fullWidth 1`] = `
<div class="mdc-text-field mdc-text-field--fullwidth"> <input class="mdc-text-field__input">
<!---->
<!---->
<!---->
</div>
`;
exports[`Text Field should render as outlined 1`] = `
<div class="mdc-text-field mdc-text-field--outlined mdc-text-field--no-label"> <input class="mdc-text-field__input">
<!---->
<div class="mdc-notched-outline mdc-notched-outline--no-label">
<div class="mdc-notched-outline__leading"></div>
<!---->
<div class="mdc-notched-outline__trailing"></div>
</div>
<!---->
<!---->
</div>
`;
exports[`Text Field should render with leading icon 1`] = `
<div class="mdc-text-field mdc-text-field--with-leading-icon mdc-text-field--no-label"><i tabindex="0" role="button" class="mdc-text-field__icon"></i> <input class="mdc-text-field__input">
<!---->
<!---->
<!---->
</div>
`;
exports[`Text Field should render with no prop 1`] = `
<div class="mdc-text-field mdc-text-field--no-label"> <input class="mdc-text-field__input">
<!---->
<!---->
<!---->
</div>
`;
exports[`Text Field should render with trailing icon 1`] = `
<div class="mdc-text-field mdc-text-field--with-trailing-icon mdc-text-field--no-label"> <input class="mdc-text-field__input">
<!---->
<!---->
<!----> <i tabindex="0" role="button" class="mdc-text-field__icon"></i> </div>
`;
2 changes: 2 additions & 0 deletions components/text-field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import TextFieldCharacterCounter from './TextFieldCharacterCounter'
import './styles.scss'

import { initPlugin } from '../'
import TextFieldIcon from './TextFieldIcon'

const plugin = {
install (vm) {
vm.component('m-text-field', TextField)
vm.component('m-text-field-helper-text', TextFieldHelperText)
vm.component('m-text-field-character-counter', TextFieldCharacterCounter)
vm.component('m-text-field-icon', TextFieldIcon)
}
}
export default plugin
Expand Down
8 changes: 4 additions & 4 deletions docs/.vuepress/components/TextfieldDemo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
style="flex: 1; margin: 2px"

>
<m-icon icon="event" slot="leadingIcon"></m-icon>
<m-text-field-icon slot="leadingIcon" class="material-icons">event</m-text-field-icon>
<m-floating-label
for="text-field1-lead">Label
</m-floating-label>
Expand All @@ -46,7 +46,7 @@
style="flex: 1; margin: 2px"

>
<m-icon icon="event" slot="trailingIcon"></m-icon>
<m-text-field-icon slot="trailingIcon" class="material-icons">event</m-text-field-icon>
<m-floating-label
for="text-field1-trail">Label
</m-floating-label>
Expand Down Expand Up @@ -84,7 +84,7 @@
outlined
style="flex:1; margin: 2px"
>
<m-icon icon="event" slot="leadingIcon"></m-icon>
<m-text-field-icon slot="leadingIcon" class="material-icons">event</m-text-field-icon>
<m-floating-label
for="text-field2-lead">Label
</m-floating-label>
Expand All @@ -104,7 +104,7 @@
<m-floating-label
for="text-field2-trail">Label
</m-floating-label>
<m-icon icon="event" slot="trailingIcon"></m-icon>
<m-text-field-icon slot="trailingIcon" class="material-icons">event</m-text-field-icon>
</m-text-field>
</div>

Expand Down

0 comments on commit 8f271f1

Please sign in to comment.