Skip to content

Commit 9292835

Browse files
committed
[+] Added normalizeProps in order to accept also non-validated props
[+] Updated SC validation component [+] v-model is now working [+] Updated examples
1 parent 26a0f75 commit 9292835

File tree

8 files changed

+115
-53
lines changed

8 files changed

+115
-53
lines changed

example/index.html

Lines changed: 56 additions & 38 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

@@ -29,22 +34,13 @@ <h1>Basic Example</h1>
2934
}
3035
`;
3136

32-
const VueComponent = {
33-
functional: true,
34-
render: function (createElement, context) {
35-
// Transparently pass any attributes, event listeners, children, etc.
36-
return createElement('button', context.data, context.children)
37-
}
38-
}
39-
40-
const StyledVueComponent = styled.default(VueComponent)``
41-
4237
// Create a <CustomTitle> vue component that renders an <h1> which is
4338
// centered, palevioletred and sized at 1.5em
4439
const CustomTitle = styled.default('h1', { animate: Boolean })`
4540
font-size: 2em;
4641
text-align: center;
4742
color: ${props => props.theme.primary};
43+
text-transform: uppercase;
4844
4945
@supports (-webkit-text-stroke: 1px) {
5046
-webkit-text-stroke: 2px ${props => props.theme.primary};
@@ -58,6 +54,16 @@ <h1>Basic Example</h1>
5854

5955
const H2 = CustomTitle.withComponent('h2')
6056

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+
6167
// Create a <Wrapper> vue component that renders a <section> with
6268
// some padding and a papayawhip background
6369
const Wrapper = styled.default.section`
@@ -79,55 +85,67 @@ <h1>Basic Example</h1>
7985
display: block;
8086
width: 100%;
8187
height: 60px;
82-
border: solid 1px ${props => props.theme.primary};
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+
}
8397
`
8498

8599
const Btn = styled.default('button', { visible: Boolean })`
86-
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};
87108
opacity: ${props => props.visible ? 1: 0};
88109
`
89110

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

94115
new Vue({
95116
el: '#container',
96117
data: {
97-
text: 'Hello World, this is my first styled component!'
98-
},
99-
methods: {
100-
input(e) {
101-
console.log(e.target.value)
102-
this.text += e.target.value
103-
}
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
104122
},
105123
template: `
106124
<theme-provider :theme="{
107125
primary: 'palevioletred',
108126
secondary: 'papayawhip',
109-
tertiary: 'goldenrod'
127+
tertiary: 'lavenderblush'
110128
}">
111-
<wrapper color="salmon">
112-
<custom-title> {{text}} </custom-title>
113-
<styled-input
114-
v-bind:value="text"
115-
v-on:input="text = $event.target.value"
116-
/>
117-
<input
118-
v-bind:value="text"
119-
v-on:input="text = $event.target.value"
120-
/>
121-
<btn visible> Button </btn>
122-
<styled-vue-component>ciao</styled-vue-component>
129+
<wrapper>
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>
123133
</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>
124139
</theme-provider>`,
125140
components: {
126-
'custom-title': H2,
127-
wrapper: W2,
128-
btn: SuperBtn,
129-
StyledVueComponent,
130-
'styled-input': StyledInput,
141+
CustomTitle,
142+
Wrapper,
143+
W2,
144+
H2,
145+
Btn,
146+
SuperBtn,
147+
SuperCustomTitle,
148+
StyledInput,
131149
'theme-provider': styled.ThemeProvider,
132150
},
133151
});

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: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import css from '../constructors/css'
2+
import normalizeProps from '../utils/normalizeProps'
23

34
export default (ComponentStyle) => {
45
const createStyledComponent = (target, rules, props) => {
5-
const prevProps = target && typeof target !== 'string'
6-
? (typeof target === 'object' ? target.props : (typeof target === 'function' ? target.options.props : {}))
7-
: {}
8-
9-
const mergedProps = { ...prevProps, ...props }
10-
116
const componentStyle = new ComponentStyle(rules)
127

8+
// handle array-declaration props
9+
const currentProps = normalizeProps(props)
10+
const prevProps = normalizeProps(target.props)
11+
1312
const StyledComponent = {
1413
inject: {
1514
$theme: {
@@ -18,8 +17,17 @@ export default (ComponentStyle) => {
1817
}
1918
}
2019
},
21-
props: mergedProps,
22-
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) {
2331
const children = []
2432
for (const slot in this.$slots) {
2533
if (slot === 'default') {
@@ -35,9 +43,16 @@ export default (ComponentStyle) => {
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,6 +72,14 @@ export default (ComponentStyle) => {
5772
return this.$theme()
5873
}
5974
},
75+
watch: {
76+
value (newValue) {
77+
this.localValue = newValue
78+
},
79+
localValue () {
80+
this.$emit('input', this.localValue)
81+
}
82+
},
6083
extend (cssRules, ...interpolations) {
6184
const extendedRules = css(cssRules, ...interpolations)
6285
return createStyledComponent(target, rules.concat(extendedRules), props)

src/utils/isStyledComponent.js

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

src/utils/isValidElementType.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import isVueComponent from './isVueComponent'
33
import isStyledComponent from './isStyledComponent'
44

55
export default function isValidElementType (target) {
6-
return isTag(target) ||
6+
return isStyledComponent(target) ||
77
isVueComponent(target) ||
8-
isStyledComponent(target)
8+
isTag(target)
99
}

src/utils/isVueComponent.js

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

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)