Skip to content

Commit 1a1b81e

Browse files
authored
Merge pull request #6 from devwiz1028/2-material_style
add material style
2 parents c7cfd3a + f7cebd8 commit 1a1b81e

File tree

4 files changed

+117
-35
lines changed

4 files changed

+117
-35
lines changed

README.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
A simple, lightweight on/off toggle component made with Vue.js. Provides multiple themes with default configurations. You can also customize size, color and borders.
44

55
<p align="center">
6-
<img src="https://i.imgur.com/8ytDSmL.png">
6+
<img src="https://i.imgur.com/Iram1NB.png">
77
</p>
88

99
## Installation
@@ -34,6 +34,27 @@ new Vue({
3434

3535
```html
3636
<onoff-toggle v-model="checked" />
37+
38+
<onoff-toggle v-model="checked" theme="ios" />
39+
40+
<onoff-toggle v-model="checked" theme="material" />
41+
42+
<onoff-toggle
43+
v-model="checked"
44+
onColor="#008F13"
45+
/>
46+
47+
<onoff-toggle
48+
v-model="checked"
49+
theme="ios"
50+
onColor="#008F13"
51+
/>
52+
53+
<onoff-toggle
54+
v-model="checked"
55+
theme="material"
56+
thumbColor="#008F13"
57+
/>
3758
```
3859

3960

@@ -48,7 +69,7 @@ new Vue({
4869
<tbody>
4970
<tr>
5071
<td>theme</td>
51-
<td>Theme to use. "default" and "ios" are available.</td>
72+
<td>Theme to use. "default", "ios" and "material" are available.</td>
5273
</tr>
5374
<tr>
5475
<td>name</td>
@@ -68,7 +89,7 @@ new Vue({
6889
</tr>
6990
<tr>
7091
<td>thumbColor</td>
71-
<td>Background color of the thumb</td>
92+
<td>Background color of the thumb. For "material" theme, if you don't specify onColor, it will be thumbColor with opacity 0.5 by default</td>
7293
</tr>
7394
<tr>
7495
<td>borderColor</td>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-onoff-toggle",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"description": "A smart, lightweight and easy-to-use on/off toggle component for Vue.js with multiple themes.",
55
"main": "src/onoff-toggle.vue",
66
"keywords": [

src/onoff-toggle.vue

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
</template>
1919

2020
<script>
21+
const THEME_DEFAULT = 'default'
22+
const THEME_IOS = 'ios'
23+
const THEME_MATERIAL = 'material'
2124
const THEMES = {
22-
'default': {
25+
[THEME_DEFAULT]: {
2326
size: {
2427
width: 75,
2528
height: 40
@@ -31,7 +34,7 @@ const THEMES = {
3134
},
3235
margin: 6
3336
},
34-
'ios': {
37+
[THEME_IOS]: {
3538
size: {
3639
width: 60,
3740
height: 36
@@ -43,18 +46,29 @@ const THEMES = {
4346
thumb: '#ffffff'
4447
},
4548
margin: 2
49+
},
50+
[THEME_MATERIAL]: {
51+
size: {
52+
width: 34,
53+
height: 14
54+
},
55+
color: {
56+
on: 'rgba(25, 118, 210, 0.5)',
57+
off: '#9f9f9f',
58+
thumb: 'rgb(25, 118, 210)',
59+
disabled: 'rgba(0, 0, 0, 0.12)'
60+
},
61+
margin: -3
4662
}
4763
}
4864
49-
function px(num) {
50-
return `${num}px`;
51-
}
65+
import { px, semiOpaqueColor } from './utils'
5266
5367
export default {
5468
name: 'OnoffToggle',
5569
props: {
5670
value: { type: Boolean, default: false },
57-
theme: { type: String, default: 'default' },
71+
theme: { type: String, default: THEME_DEFAULT },
5872
name: { type: String },
5973
disabled: { type: Boolean, default: false },
6074
onColor: { type: String },
@@ -67,7 +81,7 @@ export default {
6781
},
6882
computed: {
6983
themeInfo() {
70-
return THEMES[this.theme] || THEMES.default
84+
return THEMES[this.theme] || THEMES[THEME_DEFAULT]
7185
},
7286
labelClass() {
7387
const classNames = [
@@ -89,33 +103,49 @@ export default {
89103
const offColor = this.offColor || this.themeInfo.color.off
90104
const margin = Number(this.margin) || this.themeInfo.margin || 0
91105
const borderColor = this.borderColor || this.themeInfo.color.border
106+
const style = {
107+
width: px(width),
108+
height: px(height),
109+
borderRadius: px(height / 2),
110+
backgroundColor: this.value ? onColor : offColor
111+
}
92112
93-
if (this.theme === 'ios') {
94-
return {
95-
width: px(width),
96-
height: px(height),
97-
borderRadius: px(height / 2),
113+
if (this.theme === THEME_IOS) {
114+
Object.assign(style, {
98115
backgroundColor: offColor,
99116
boxShadow: `inset 0 0 0 ${this.value ? height / 2 : 0}px ${onColor}, 0 0 0 ${margin}px ${this.value ? onColor : borderColor}`
117+
})
118+
} else if (this.theme === THEME_MATERIAL) {
119+
if (this.disabled) {
120+
Object.assign(style, {
121+
backgroundColor: THEMES[THEME_MATERIAL].color.disabled,
122+
opacity: 1
123+
})
124+
} else if (this.value && !this.onColor && this.thumbColor) {
125+
style.backgroundColor = semiOpaqueColor(this.thumbColor, 0.5)
100126
}
101127
}
102128
103-
return {
104-
width: px(width),
105-
height: px(height),
106-
borderRadius: px(height / 2),
107-
backgroundColor: this.value ? onColor : offColor
108-
}
129+
return style
109130
},
110131
thumbStyle() {
111132
const margin = Number(this.margin) || this.themeInfo.margin || 0
112133
const size = this.bodyHeight - (margin * 2)
113134
const color = this.thumbColor || this.themeInfo.color.thumb
114135
const left = this.value ? (this.bodyWidth - size - margin) : margin
115136
const borderColor = this.borderColor || this.themeInfo.color.border
137+
const style = {
138+
width: px(size),
139+
height: px(size),
140+
left: px(left),
141+
top: px(margin),
142+
borderRadius: px(size / 2),
143+
backgroundColor: color,
144+
boxShadow: '0px 1px 3px 0px rgba(0, 0, 0, 0.1)'
145+
}
116146
117-
if (this.theme === 'ios') {
118-
return {
147+
if (this.theme === THEME_IOS) {
148+
Object.assign(style, {
119149
width: px(this.bodyHeight),
120150
height: px(this.bodyHeight),
121151
left: this.value ? `calc(100% - ${this.bodyHeight}px)` : px(0),
@@ -125,17 +155,19 @@ export default {
125155
boxShadow: this.value
126156
? `0 0 0 ${margin}px transparent, 0 3px 3px rgba(0, 0, 0, 0.3)`
127157
: `0 3px 3px rgba(0, 0, 0, 0.2), 0 0 0 ${margin}px ${borderColor}`
158+
})
159+
} else if (this.theme === THEME_MATERIAL) {
160+
Object.assign(style, {
161+
backgroundColor: this.value ? color : '#ffffff',
162+
transition: 'left 0.15s',
163+
boxShadow: '0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12)'
164+
})
165+
if (this.disabled) {
166+
style.backgroundColor = '#bdbdbd'
128167
}
129168
}
130169
131-
return {
132-
width: px(size),
133-
height: px(size),
134-
left: px(left),
135-
top: px(margin),
136-
borderRadius: px(size / 2),
137-
backgroundColor: color
138-
}
170+
return style
139171
},
140172
bodyWidth() {
141173
return Number(this.width) || this.themeInfo.size.width
@@ -170,7 +202,4 @@ export default {
170202
position: absolute;
171203
transition: all 0.3s;
172204
}
173-
.v-toggle-default .v-toggle_thumb {
174-
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.1);
175-
}
176205
</style>

src/utils.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
function parseColor(c) {
2+
let cache
3+
const p = parseInt,
4+
color = c.replace(/\s/g,'')
5+
6+
if ((cache = /#([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})/.exec(color))) {
7+
cache = [p(cache[1], 16), p(cache[2], 16), p(cache[3], 16)]
8+
} else if ((cache = /#([\da-fA-F])([\da-fA-F])([\da-fA-F])/.exec(color))) {
9+
cache = [p(cache[1], 16) * 17, p(cache[2], 16) * 17, p(cache[3], 16) * 17]
10+
} else if ((cache = /rgba\(([\d]+),([\d]+),([\d]+),([\d]+|[\d]*.[\d]+)\)/.exec(color))) {
11+
cache = [+cache[1], +cache[2], +cache[3], +cache[4]]
12+
} else if ((cache = /rgb\(([\d]+),([\d]+),([\d]+)\)/.exec(color))) {
13+
cache = [+cache[1], +cache[2], +cache[3]]
14+
} else {
15+
cache = [0, 0, 0, 1]
16+
}
17+
18+
if (isNaN(cache[3])) {
19+
cache[3] = 1
20+
}
21+
22+
return cache.slice(0, 4)
23+
}
24+
25+
export function px(val) {
26+
return (typeof val === 'number') ? `${val}px` : val
27+
}
28+
29+
export function semiOpaqueColor(color, opacity) {
30+
const rgba = parseColor(color)
31+
return `rgba(${rgba[0]}, ${rgba[1]}, ${rgba[2]}, ${rgba[3] * opacity})`
32+
}

0 commit comments

Comments
 (0)