Skip to content

Commit 2b81930

Browse files
authored
Merge pull request #88 from liqueflies/master
[+] Added v-model and better styled-component check
2 parents 8dbfd72 + 9292835 commit 2b81930

File tree

9 files changed

+153
-40
lines changed

9 files changed

+153
-40
lines changed

example/index.html

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ <h1>Basic Example</h1>
1616
styled.injectGlobal`
1717
body {
1818
background-color: #fefefe;
19+
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
20+
}
21+
22+
*, *::before, *::after {
23+
box-sizing: border-box;
1924
}
2025
`;
2126

@@ -31,29 +36,43 @@ <h1>Basic Example</h1>
3136

3237
// Create a <CustomTitle> vue component that renders an <h1> which is
3338
// centered, palevioletred and sized at 1.5em
34-
const CustomTitle = styled.default.h1`
39+
const CustomTitle = styled.default('h1', { animate: Boolean })`
3540
font-size: 2em;
3641
text-align: center;
3742
color: ${props => props.theme.primary};
38-
animation: ${animation} 2s linear infinite;
43+
text-transform: uppercase;
3944
4045
@supports (-webkit-text-stroke: 1px) {
4146
-webkit-text-stroke: 2px ${props => props.theme.primary};
4247
color: transparent
4348
}
49+
50+
${props => props.animate &&
51+
`animation: ${animation} 2s linear infinite;`
52+
}
4453
`;
4554

4655
const H2 = CustomTitle.withComponent('h2')
4756

57+
const MyComponent = {
58+
props: ['visible'],
59+
template: `<h1><slot /></h1>`
60+
}
61+
62+
const SuperCustomTitle = styled.default(MyComponent, { color: String })`
63+
color: ${props => props.color || 'red'};
64+
opacity: ${props => props.visible ? 1 : 0};
65+
`
66+
4867
// Create a <Wrapper> vue component that renders a <section> with
4968
// some padding and a papayawhip background
5069
const Wrapper = styled.default.section`
5170
padding: 4em;
5271
background: ${props => props.theme.secondary};
5372
`;
5473

55-
const W2 = styled.default(Wrapper)`
56-
color: red;
74+
const W2 = Wrapper.extend`
75+
background: ${props => props.theme.tertiary};
5776
`;
5877

5978
const W3 = styled.default(W2)`
@@ -62,32 +81,72 @@ <h1>Basic Example</h1>
6281
}
6382
`
6483

84+
const StyledInput = styled.default.input`
85+
display: block;
86+
width: 100%;
87+
height: 60px;
88+
border: solid 3px transparent;
89+
padding: 0 0.6em;
90+
font-size: 1em;
91+
line-height: 1;
92+
93+
&:focus {
94+
outline: none;
95+
border: solid 3px ${props => props.theme.primary};
96+
}
97+
`
98+
6599
const Btn = styled.default('button', { visible: Boolean })`
66-
background-color: red;
100+
outline: none;
101+
border: none;
102+
border-radius: 6em;
103+
padding: 1em 2em;
104+
color: #fff;
105+
cursor: pointer;
106+
margin: 1.5em 0;
107+
background-color: ${props => props.theme.primary};
67108
opacity: ${props => props.visible ? 1: 0};
68109
`
69110

70111
const SuperBtn = styled.default(Btn, { visible: Boolean, big: Boolean })`
71-
font-size: ${props => props.big ? 22 : 18}px;
112+
font-size: ${props => props.big ? 0.8 : 1}em;
72113
`
73114

74115
new Vue({
75116
el: '#container',
117+
data: {
118+
text1: 'Hello World, this is my first styled component!',
119+
text2: 'Hello World, this is my first styled component!',
120+
animated1: false,
121+
animated2: false
122+
},
76123
template: `
77124
<theme-provider :theme="{
78125
primary: 'palevioletred',
79-
secondary: 'papayawhip'
126+
secondary: 'papayawhip',
127+
tertiary: 'lavenderblush'
80128
}">
81129
<wrapper>
82-
<custom-title> Hello World, this is my first styled component! </custom-title>
83-
<btn visible> Button </btn>
130+
<custom-title :visible="true" :animate="animated1"> {{text1}} </custom-title>
131+
<styled-input v-model="text1" />
132+
<btn visible @click="animated1 = !animated1"> A Styled Button </btn>
84133
</wrapper>
134+
<w-2>
135+
<h-2 :animate="animated2"> {{text2}} </h-2>
136+
<styled-input v-model="text2" />
137+
<super-btn visible @click="animated2 = !animated2"> An extension of Styled Button </super-btn>
138+
</w-2>
85139
</theme-provider>`,
86140
components: {
87-
'custom-title': H2,
88-
wrapper: W3,
89-
btn: SuperBtn,
90-
'theme-provider': styled.ThemeProvider
141+
CustomTitle,
142+
Wrapper,
143+
W2,
144+
H2,
145+
Btn,
146+
SuperBtn,
147+
SuperCustomTitle,
148+
StyledInput,
149+
'theme-provider': styled.ThemeProvider,
91150
},
92151
});
93152
</script>

package-lock.json

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"glamor": "^2.20.24",
3838
"inline-style-prefixer": "^2.0.5",
3939
"lodash.isplainobject": "^4.0.6",
40+
"lodash.zipobject": "^4.1.3",
4041
"stylis": "^3.5.4"
4142
},
4243
"devDependencies": {

src/models/StyledComponent.js

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import css from '../constructors/css'
2+
import normalizeProps from '../utils/normalizeProps'
3+
14
export default (ComponentStyle) => {
25
const createStyledComponent = (target, rules, props) => {
3-
const prevProps = target && typeof target !== 'string'
4-
? (typeof target === 'object' ? target.props : (typeof target === 'function' ? target.options.props : {}))
5-
: {}
6-
7-
const mergedProps = { ...prevProps, ...props }
8-
96
const componentStyle = new ComponentStyle(rules)
107

8+
// handle array-declaration props
9+
const currentProps = normalizeProps(props)
10+
const prevProps = normalizeProps(target.props)
11+
1112
const StyledComponent = {
1213
inject: {
1314
$theme: {
@@ -16,8 +17,17 @@ export default (ComponentStyle) => {
1617
}
1718
}
1819
},
19-
props: mergedProps,
20-
render: function (createElement) {
20+
props: {
21+
value: null,
22+
...currentProps,
23+
...prevProps
24+
},
25+
data () {
26+
return {
27+
localValue: this.value
28+
}
29+
},
30+
render (createElement) {
2131
const children = []
2232
for (const slot in this.$slots) {
2333
if (slot === 'default') {
@@ -27,17 +37,22 @@ export default (ComponentStyle) => {
2737
}
2838
}
2939

30-
console.log()
31-
3240
return createElement(
3341
target,
3442
{
3543
class: [this.generatedClassName],
3644
props: this.$props,
3745
domProps: {
38-
value: this.value
46+
value: this.localValue
47+
},
48+
on: {
49+
...this.$listeners,
50+
input: event => {
51+
if (event && event.target) {
52+
this.localValue = event.target.value
53+
}
54+
}
3955
},
40-
on: this.$listeners,
4156
scopedSlots: this.$scopedSlots
4257
},
4358
children
@@ -57,8 +72,17 @@ export default (ComponentStyle) => {
5772
return this.$theme()
5873
}
5974
},
60-
extend (extendedRules) {
61-
return createStyledComponent(target, rules.slice().concat(extendedRules), props)
75+
watch: {
76+
value (newValue) {
77+
this.localValue = newValue
78+
},
79+
localValue () {
80+
this.$emit('input', this.localValue)
81+
}
82+
},
83+
extend (cssRules, ...interpolations) {
84+
const extendedRules = css(cssRules, ...interpolations)
85+
return createStyledComponent(target, rules.concat(extendedRules), props)
6286
},
6387
withComponent (newTarget) {
6488
return createStyledComponent(newTarget, rules, props)

src/utils/isStyledComponent.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default function isStyledComponent (target) {
2+
return target &&
3+
target.methods &&
4+
typeof target.methods.generateAndInjectStyles() === 'string'
5+
}

src/utils/isTag.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
import domElements from './domElements'
3+
4+
export default function isTag (target) {
5+
if (typeof target === 'string') {
6+
return domElements.indexOf(target) !== -1
7+
}
8+
}

src/utils/isValidElementType.js

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
import domElements from './domElements'
1+
import isTag from './isTag'
2+
import isVueComponent from './isVueComponent'
3+
import isStyledComponent from './isStyledComponent'
24

3-
export default function isValidElementType (tag) {
4-
if (typeof tag === 'undefined' || typeof tag === 'number') {
5-
return false
6-
}
7-
if (typeof tag === 'string') {
8-
return domElements.indexOf(tag) !== -1
9-
}
10-
if (typeof tag === 'object') {
11-
return !!tag.template || !!tag.withComponent
12-
}
13-
return true
5+
export default function isValidElementType (target) {
6+
return isStyledComponent(target) ||
7+
isVueComponent(target) ||
8+
isTag(target)
149
}

src/utils/isVueComponent.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function isVueComponent (target) {
2+
return target &&
3+
(
4+
typeof target.render === 'function' ||
5+
typeof target.template === 'string'
6+
)
7+
}

src/utils/normalizeProps.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import zipObject from 'lodash.zipobject'
2+
3+
export default function normalizeProps (props = {}) {
4+
if (Array.isArray(props)) {
5+
return zipObject(props)
6+
} else {
7+
return props
8+
}
9+
}

0 commit comments

Comments
 (0)