Skip to content
This repository was archived by the owner on Apr 25, 2020. It is now read-only.

Commit 60e97bc

Browse files
committed
Merge branch 'pr/6'
Fix #3 Fix #6
2 parents d4da2fc + e3abf88 commit 60e97bc

File tree

5 files changed

+152
-58
lines changed

5 files changed

+152
-58
lines changed

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,25 @@ Load script and stylesheet files from CDN:
8888

8989
## Usage
9090

91-
Wrap text/email/password input or textarea with `<float-label>`:
91+
Wrap input, textarea or select with `<float-label>`:
9292

9393
```html
9494
<float-label>
9595
<input type="email" placeholder="E-mail">
9696
</float-label>
9797

9898
<float-label>
99-
<textarea placeholder="comment"></textarea>
99+
<textarea placeholder="Comment"></textarea>
100+
</float-label>
101+
102+
<float-label>
103+
<select>
104+
<option disabled selected>Framework</option>
105+
<option>Vue</option>
106+
<option>React</option>
107+
<option>Angular</option>
108+
<option>Ember</option>
109+
</select>
100110
</float-label>
101111
```
102112

@@ -141,7 +151,13 @@ to meet your design requirements:
141151
$ git clone [email protected]:bkzl/vue-float-label.git
142152
```
143153

144-
2. Start development:
154+
2. Install dependencies:
155+
156+
```sh
157+
$ yarn install
158+
```
159+
160+
3. Start development:
145161

146162
```sh
147163
$ npm start

components/FloatLabel.vue

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="vfl-has-label">
3-
<div class="vfl-label" :class="classObject" :style="{ width }" @click="focusInput">
3+
<div class="vfl-label" :class="classObject" :style="{ width }" @click="focusFormEl">
44
{{ label }}
55
</div>
66
<slot></slot>
@@ -12,25 +12,27 @@ export default {
1212
name: 'float-label',
1313
data () {
1414
return {
15-
input: undefined,
15+
formEl: undefined,
1616
hasValue: false,
17-
isActive: false,
18-
label: '',
19-
width: 'auto'
17+
isActive: false
2018
}
2119
},
2220
mounted () {
23-
this.input = this.$el.querySelector('input, textarea')
24-
this.width = `${this.input.clientWidth}px`
25-
this.label = this.input.placeholder
26-
this.input.addEventListener('input', this.updateHasValue)
27-
this.input.addEventListener('input', this.updateIsActive)
28-
this.input.addEventListener('blur', this.updateIsActive)
29-
this.input.addEventListener('focus', this.updateIsActive)
21+
this.formEl = this.$el.querySelector('input, textarea, select')
22+
this.formEl.addEventListener('input', this.updateHasValue)
23+
this.formEl.addEventListener('input', this.updateIsActive)
24+
this.formEl.addEventListener('blur', this.updateIsActive)
25+
this.formEl.addEventListener('focus', this.updateIsActive)
26+
},
27+
beforyDestroy () {
28+
this.formEl.removeEventListener('input', this.updateHasValue)
29+
this.formEl.removeEventListener('input', this.updateIsActive)
30+
this.formEl.removeEventListener('blur', this.updateIsActive)
31+
this.formEl.removeEventListener('focus', this.updateIsActive)
3032
},
3133
methods: {
32-
focusInput () {
33-
this.input.focus()
34+
focusFormEl () {
35+
this.formEl.focus()
3436
},
3537
updateHasValue (e) {
3638
this.hasValue = e.target.value.length > 0
@@ -45,6 +47,23 @@ export default {
4547
'vfl-label-on-input': this.hasValue,
4648
'vfl-label-on-focus': this.isActive
4749
}
50+
},
51+
formElType () {
52+
return this.formEl ? this.formEl.tagName.toLowerCase() : ''
53+
},
54+
width () {
55+
return this.formEl ? `${this.formEl.clientWidth}px` : 'auto'
56+
},
57+
label () {
58+
switch (this.formElType) {
59+
case 'input':
60+
case 'textarea':
61+
return this.formEl.placeholder
62+
case 'select':
63+
return this.formEl.querySelector('option[disabled][selected]').innerHTML
64+
default:
65+
return ''
66+
}
4867
}
4968
}
5069
}
@@ -65,12 +84,14 @@ export default {
6584
color: #aaa;
6685
text-overflow: ellipsis;
6786
white-space: nowrap;
87+
pointer-events: none;
6888
opacity: 0;
6989
transition: all 0.2s ease-out;
7090
}
7191
7292
.vfl-label-on-input {
7393
top: -1.3em;
94+
pointer-events: all;
7495
opacity: 1;
7596
}
7697
@@ -79,7 +100,8 @@ export default {
79100
}
80101
81102
.vfl-has-label input:focus,
82-
.vfl-has-label textarea:focus {
103+
.vfl-has-label textarea:focus,
104+
.vfl-has-label select:focus {
83105
outline: 0;
84106
}
85107
</style>

demo/Demo.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@
1717
<textarea placeholder="Comment"></textarea>
1818
</float-label>
1919

20+
<float-label>
21+
<select>
22+
<option disabled selected>Framework</option>
23+
<option>Vue</option>
24+
<option>React</option>
25+
<option>Angular</option>
26+
<option>Ember</option>
27+
</select>
28+
</float-label>
29+
2030
<div class="example">
2131
<float-label>
2232
<input type="text" placeholder="Website">

test/components/FloatLabel.test.js

Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,78 @@
1-
import Vue from 'vue'
2-
import FloatLabel from 'components/FloatLabel'
1+
import { ctorInput, ctorTextArea, ctorSelect } from '../helpers'
32

4-
const getFloatLabel = () => {
5-
return new Vue({
6-
components: { FloatLabel },
7-
render: h => {
8-
return h('float-label', [
9-
h('input', {
10-
attrs: {
11-
type: 'text',
12-
placeholder: 'Name'
13-
}
14-
})
15-
])
16-
}
17-
}).$mount().$children[0]
18-
}
3+
test('label', () => {
4+
expect(ctorInput().label).toEqual('Name')
5+
expect(ctorTextArea().label).toEqual('Comment')
6+
expect(ctorSelect().label).toEqual('Framework')
7+
})
8+
9+
test('formEl', () => {
10+
expect(ctorInput().formEl).toBeInstanceOf(HTMLInputElement)
11+
expect(ctorTextArea().formEl).toBeInstanceOf(HTMLTextAreaElement)
12+
expect(ctorSelect().formEl).toBeInstanceOf(HTMLSelectElement)
13+
})
1914

20-
test('setup on mount', () => {
21-
const vm = getFloatLabel()
22-
expect(vm.input).toBeInstanceOf(HTMLInputElement)
23-
expect(vm.label).toEqual('Name')
15+
test('formElType', () => {
16+
expect(ctorInput().formElType).toEqual('input')
17+
expect(ctorTextArea().formElType).toEqual('textarea')
18+
expect(ctorSelect().formElType).toEqual('select')
2419
})
2520

2621
test('classObject', () => {
27-
const vm = getFloatLabel()
22+
const vm = ctorInput()
2823
const classObjectKeys = Object.keys(vm.classObject)
2924
expect(classObjectKeys).toContain('vfl-label-on-input')
3025
expect(classObjectKeys).toContain('vfl-label-on-focus')
3126
})
3227

33-
test('focusInput', () => {
34-
const vm = getFloatLabel()
35-
vm.input.focus = jest.fn()
36-
vm.focusInput()
37-
expect(vm.input.focus).toHaveBeenCalledTimes(1)
28+
test('focusFormEl', () => {
29+
const vm = ctorInput()
30+
vm.formEl.focus = jest.fn()
31+
vm.focusFormEl()
32+
expect(vm.formEl.focus).toHaveBeenCalledTimes(1)
3833
})
3934

4035
describe('updateHasValue', () => {
4136
test('hasValue is true when element value isnt empty', () => {
42-
const vm = getFloatLabel()
43-
const event = { target: vm.input }
44-
vm.input.value = 'Foo'
37+
const vm = ctorInput()
38+
const event = { target: vm.formEl }
39+
vm.formEl.value = 'Foo'
4540
vm.updateHasValue(event)
4641
expect(vm.hasValue).toEqual(true)
4742
})
4843

4944
test('hasValue is false when element value is empty', () => {
50-
const vm = getFloatLabel()
51-
const event = { target: vm.input }
52-
vm.input.value = ''
45+
const vm = ctorInput()
46+
const event = { target: vm.formEl }
47+
vm.formEl.value = ''
5348
vm.updateHasValue(event)
5449
expect(vm.hasValue).toEqual(false)
5550
})
5651
})
5752

5853
describe('updateIsActive', () => {
5954
test('isActive is true when element is focused and has content', () => {
60-
const vm = getFloatLabel()
61-
const event = { target: vm.input }
55+
const vm = ctorInput()
56+
const event = { target: vm.formEl }
6257
vm.hasValue = true
63-
vm.input.focus()
58+
vm.formEl.focus()
6459
vm.updateIsActive(event)
6560

6661
expect(vm.isActive).toEqual(true)
6762
})
6863

6964
test('isActive is false when element isnt focused and has content', () => {
70-
const vm = getFloatLabel()
71-
const event = { target: vm.input }
65+
const vm = ctorInput()
66+
const event = { target: vm.formEl }
7267
vm.hasValue = true
7368
vm.updateIsActive(event)
7469

7570
expect(vm.isActive).toEqual(false)
7671
})
7772

7873
test('isActive is false when element isnt focused and doesnt have content', () => {
79-
const vm = getFloatLabel()
80-
const event = { target: vm.input }
74+
const vm = ctorInput()
75+
const event = { target: vm.formEl }
8176
vm.updateIsActive(event)
8277

8378
expect(vm.isActive).toEqual(false)

test/helpers.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import Vue from 'vue'
2+
import FloatLabel from 'components/FloatLabel'
3+
4+
export const ctorInput = () => {
5+
return new Vue({
6+
components: { FloatLabel },
7+
render: h => {
8+
return h('float-label', [
9+
h('input', {
10+
attrs: {
11+
type: 'text',
12+
placeholder: 'Name'
13+
}
14+
})
15+
])
16+
}
17+
}).$mount().$children[0]
18+
}
19+
20+
export const ctorTextArea = () => {
21+
return new Vue({
22+
components: { FloatLabel },
23+
render: h => {
24+
return h('float-label', [
25+
h('textarea', {
26+
attrs: {
27+
placeholder: 'Comment'
28+
}
29+
})
30+
])
31+
}
32+
}).$mount().$children[0]
33+
}
34+
35+
export const ctorSelect = () => {
36+
return new Vue({
37+
components: { FloatLabel },
38+
render: h => {
39+
return h('float-label', [
40+
h('select', [
41+
h('option', {
42+
attrs: {
43+
disabled: 'disabled',
44+
selected: 'selected'
45+
}
46+
}, 'Framework')
47+
])
48+
])
49+
}
50+
}).$mount().$children[0]
51+
}

0 commit comments

Comments
 (0)