Skip to content

Commit

Permalink
feat(textfield): refactor foundation and markup as per mdc 0.28.0
Browse files Browse the repository at this point in the history
  • Loading branch information
stasson committed Jan 13, 2018
1 parent eb372d2 commit 70dfab9
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 96 deletions.
1 change: 1 addition & 0 deletions components/textfield/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var vm = new Vue({
|`v-model`| String || binds textfield value |
|`dense`| Boolean | | compresses the textfield to make it slightly smaller |
|`label`| String | | hint text |
|`outline`| Boolean | | whether the textfield is outlined |
|`box`| Boolean | | whether the textfield is a box |
|`helptext`| String | | help text |
|`helptext-persistent`| Boolean | | whether help text is persistent |
Expand Down
13 changes: 10 additions & 3 deletions components/textfield/demo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@
<mdc-layout-grid>
<mdc-layout-cell span=6>
<mdc-textfield :disabled="!enabled" v-model="textField"
label="Simple textfield"></mdc-textfield>
<mdc-textfield :disabled="!enabled" v-model="textField"
label="with help text"
label="textfield"
helptext="Help text..."></mdc-textfield>
<mdc-textfield :disabled="!enabled" v-model="textField"
label="outlined" outline
helptext="Help text..."
></mdc-textfield>
<mdc-textfield :disabled="!enabled" v-model="textField"
label="in a box"
helptext="Help text..." box></mdc-textfield>
</mdc-layout-cell>
<mdc-layout-cell span=6>
<p><mdc-textfield :disabled="!enabled" v-model="textField" multiline
rows="10"
label="multiline" ></mdc-textfield></p>
</mdc-layout-cell>
<mdc-layout-cell span=12>
<p><mdc-textfield :disabled="!enabled" v-model="textField" fullwidth
label="full width" ></mdc-textfield></p>
</mdc-layout-cell>
</mdc-layout-grid>
</div>
</template>
Expand Down
235 changes: 142 additions & 93 deletions components/textfield/mdc-textfield.vue
Original file line number Diff line number Diff line change
@@ -1,100 +1,75 @@
<template>
<div class="mdc-textfield-wrapper">
<!--fullwidth multiline case-->
<div ref="root" :class="rootClasses" v-if="multiline && fullwidth">
<textarea ref="input" :class="inputClasses"
<div class="mdc-textfield-wrapper" :style="{width:fullwidth?'100%':undefined}">
<div ref="root" :class="rootClasses">
<custom-element ref="input"
:tag="inputTag"
:rows="inputRows"
:cols="inputCols"
:value="value" @input="updateValue($event.target.value)"
:rows="rows"
:class="inputClasses" :required="required"
:minlength="minlength" :maxlength="maxlength"
:aria-controls="'help-'+_uid"
:placeholder="label"
:aria-label="label"
></textarea>
</div>

<!--multiline case-->
<div ref="root" :class="rootClasses" v-else-if="multiline">
<textarea ref="input" :class="inputClasses" :id="_uid"
:value="value" @input="updateValue($event.target.value)"
:rows="rows" :cols="cols"
:minlength="minlength" :maxlength="maxlength"
:aria-controls="'help-'+_uid"
></textarea>
<label ref="label" :class="labelClassesUpgraded" :for="_uid" v-if="label">
{{ label }}
</label>
</div>

<!--fullwidth case: no label -->
<div ref="root" :class="rootClasses" v-else-if="fullwidth">
<input ref="input" :class="inputClasses" :type="type"
:value="value" @input="updateValue($event.target.value)"
:required="required"
:minlength="minlength" :maxlength="maxlength"
:aria-controls="'help-'+_uid"
:placeholder="label"
:aria-label="label"
>
</div>

<!--default case -->
<div ref="root" :class="rootClasses" v-else>
<input ref="input" :class="inputClasses" :type="type" :id="_uid"
:value="value" @input="updateValue($event.target.value)"
:required="required" :size="size"
:minlength="minlength" :maxlength="maxlength"
:aria-controls="'help-'+_uid"
>
<label ref="label" :class="labelClassesUpgraded" :for="_uid" v-if="label">
:placeholder="inputPlaceHolder"
:aria-label="inputPlaceHolder"
:aria-controls="inputAriaControls"
/>
<label ref="label" :class="labelClassesUpgraded" :for="_uid" v-if="hasLabel">
{{ label }}
</label>
<div ref="bottom" :class="bottomClasses"></div>
<div ref="outline" class="mdc-text-field__outline" v-if="hasOutline">
<svg>
<path class="mdc-text-field__outline-path" :d="outlinePathAttr" />
</svg>
</div>
<div class="mdc-text-field__idle-outline" v-if="hasOutline"></div>
<div ref="bottom" :class="bottomClasses" v-if="hasBottomLine"></div>
</div>

<!--help text -->
<p ref="help" :id="'help-'+_uid" :class="helpClasses"
aria-hidden="true" v-if="helptext">
{{ helptext }}
</p>

</div>
</template>

<script>
import MDCTextfieldFoundation from '@material/textfield/foundation'
import MDCTextFieldBottomLineFoundation from '@material/textfield/bottom-line/foundation'
import MDCTextFieldHelperTextFoundation from '@material/textfield/helper-text/foundation'
import {emitCustomEvent, DispatchFocusMixin} from '../base'
import MDCTextFieldIconFoundation from '@material/textfield/icon/foundation';
import MDCTextFieldLabelFoundation from '@material/textfield/label/foundation';
import MDCTextFieldOutlineFoundation from '@material/textfield/outline/foundation';
import {emitCustomEvent, DispatchFocusMixin, CustomElementMixin} from '../base'
import {RippleBase} from '../ripple'
export default {
name: 'mdc-textfield',
mixins: [DispatchFocusMixin],
mixins: [CustomElementMixin, DispatchFocusMixin],
props: {
'value': String,
'type': {
value: String,
type: {
type: String,
default: 'text',
validator: function (value) {
return ['text', 'email', 'search', 'password', 'tel', 'url']
.indexOf(value) !== -1
}
},
'dense': Boolean,
'label': String,
'helptext': String,
'helptext-persistent': Boolean,
'helptext-validation': Boolean,
'box': Boolean,
'disabled': Boolean,
'required': Boolean,
'minlength': { type: [Number, String], default: undefined },
'maxlength': { type: [Number, String], default: undefined },
'size': { type: [Number, String], default: 20 },
'fullwidth': Boolean,
'multiline': Boolean,
'rows': { type: [Number, String], default: 8 },
'cols': { type: [Number, String], default: 40 }
dense: Boolean,
label: String,
helptext: String,
helptextPersistent: Boolean,
helptextValidation: Boolean,
box: Boolean,
outline: Boolean,
disabled: Boolean,
required: Boolean,
minlength: { type: [Number, String], default: undefined },
maxlength: { type: [Number, String], default: undefined },
size: { type: [Number, String], default: 20 },
fullwidth: Boolean,
multiline: Boolean,
rows: { type: [Number, String], default: 8 },
cols: { type: [Number, String], default: 40 }
},
data: function () {
return {
Expand All @@ -107,7 +82,8 @@ export default {
'mdc-text-field--dense': this.dense,
'mdc-text-field--fullwidth': this.fullwidth,
'mdc-text-field--textarea': this.multiline,
'mdc-text-field--box': this.box
'mdc-text-field--box': this.box,
'mdc-text-field--outlined': this.outline
},
inputClasses: {
'mdc-text-field__input': true
Expand All @@ -122,7 +98,8 @@ export default {
'mdc-text-field-helper-text': true,
'mdc-text-field-helper-text--persistent': this.helptextPersistent,
'mdc-text-field-helper-text--validation-msg': this.helptextValidation
}
},
outlinePathAttr: undefined,
}
},
watch: {
Expand All @@ -136,13 +113,38 @@ export default {
}
},
computed: {
inputTag () {
return this.multiline ? 'textarea' : 'input'
},
inputRows () {
return this.multiline ? this.rows : undefined
},
inputCols () {
return this.multiline ? this.cols : undefined
},
inputPlaceHolder () {
return this.fullwidth ? this.label : undefined
},
inputAriaControls () {
return this.help ? 'help-' + this._uid: undefined
},
hasLabel () {
return this.label && !this.fullwidth
},
hasOutline () {
return this.outline
},
hasBottomLine () {
return !this.outline && !this.multiline
},
labelClassesUpgraded () {
return Object.assign(this.labelClasses, {
'mdc-text-field__label--float-above': this.value
})
}
},
mounted () {
if (this.$refs.bottom) {
this.bottomLineFoundation = new MDCTextFieldBottomLineFoundation({
addClass: (className) => {
Expand Down Expand Up @@ -187,46 +189,68 @@ export default {
removeAttr: (name) => {
this.$refs.help.removeAttribute(name)
},
setContent: (content) => {
this.$refs.help.textContent = content;
setContent: ( /*content*/) => {
// help text get's updated from {{helptext}}
// this.$refs.help.textContent = content;
}
})
this.helperTextFoundation.init()
}
if (this.$refs.icon) {
this.iconFoundation = new MDCTextFieldIconFoundation({
setAttr: (attr, value) => this.$refs.icon.setAttribute(attr, value),
registerInteractionHandler: (evtType, handler) => {
this.$refs.icon.addEventListener(evtType, handler)
},
deregisterInteractionHandler: (evtType, handler) => {
this.$refs.icon.removeEventListener(evtType, handler)
},
notifyIconAction: () => this.$emit('icon-action')
})
this.iconFoundation.init()
}
if (this.$refs.label) {
this.labelFoundation = new MDCTextFieldLabelFoundation({
addClass: (className) => {
this.$set(this.labelClasses, className, true)
},
removeClass: (className) => {
this.$delete(this.labelClasses, className)
},
getWidth: () => this.$refs.label.offsetWidth,
})
this.labelFoundation.init()
}
if (this.$refs.outline) {
this.outlineFoundation = new MDCTextFieldOutlineFoundation({
getWidth: () => this.$refs.outline.offsetWidth,
getHeight: () => this.$refs.outline.offsetHeight,
setOutlinePathAttr: (value) => {
this.outlinePathAttr = value
},
})
this.outlineFoundation.init()
}
this.foundation = new MDCTextfieldFoundation({
addClass: (className) => {
this.$set(this.rootClasses, className, true)
},
removeClass: (className) => {
this.$delete(this.rootClasses, className)
},
addClassToLabel: (className) => {
this.$set(this.labelClasses, className, true)
hasClass: (className) => {
this.$refs.root.classList.contains(className)
},
removeClassFromLabel: (className) => {
this.$delete(this.labelClasses, className)
},
setIconAttr: (/* name: string, value: string */) => {},
eventTargetHasClass: (target, className) => target.classList.contains(className),
registerTextFieldInteractionHandler: (evtType, handler) => {
this.$refs.root.addEventListener(evtType, handler)
},
deregisterTextFieldInteractionHandler: (evtType, handler) => {
this.$refs.root.removeEventListener(evtType, handler)
},
registerInputInteractionHandler: (evtType, handler) => {
this.$refs.input.addEventListener(evtType, handler)
},
deregisterInputInteractionHandler: (evtType, handler) => {
this.$refs.input.removeEventListener(evtType, handler)
},
getNativeInput: () => {
return this.$refs.input
},
notifyIconAction: () => {
this.$emit('icon')
},
registerBottomLineEventHandler: (evtType, handler) => {
if (this.$refs.bottom) {
this.$refs.bottom.addEventListener(evtType, handler);
Expand All @@ -237,9 +261,32 @@ export default {
this.$refs.bottom.removeEventListener(evtType, handler);
}
},
getIdleOutlineStyleValue: (propertyName) => {
const idleOutlineElement = this.$refs.outline
if (idleOutlineElement) {
return window.getComputedStyle(idleOutlineElement).getPropertyValue(propertyName);
}
},
isFocused: () => {
return document.activeElement === this.$refs.input
},
isRtl: () => window.getComputedStyle(this.$refs.root).getPropertyValue('direction') === 'rtl',
registerInputInteractionHandler: (evtType, handler) => {
this.$refs.input.addEventListener(evtType, handler)
},
deregisterInputInteractionHandler: (evtType, handler) => {
this.$refs.input.removeEventListener(evtType, handler)
},
getNativeInput: () => {
return this.$refs.input
},
}, {
bottomLine: this.bottomLineFoundation,
helperText: this.helperTextFoundation
helperText: this.helperTextFoundation,
icon: this.iconFoundation,
label: this.labelFoundation,
outline: this.outlineFoundation,
})
this.foundation.init()
Expand All @@ -250,12 +297,14 @@ export default {
this.ripple.init()
}
},
beforeDestroy () {
this.foundation && this.foundation.destroy()
this.bottomLineFoundation && this.bottomLineFoundation.destroy()
this.helperTextFoundation && this.helperTextFoundation.destroy()
this.iconFoundation && this.iconFoundation.destroy()
this.labelFoundation && this.labelFoundation.destroy()
this.outlineFoundation && this.outlineFoundation.destroy()
this.ripple && this.ripple.destroy()
}
}
Expand Down

0 comments on commit 70dfab9

Please sign in to comment.