Skip to content

Commit 319c17d

Browse files
authored
Merge pull request #44 from cssinjs/feature/component-selectors
Component Selectors
2 parents 826ce34 + 07969d9 commit 319c17d

7 files changed

Lines changed: 121 additions & 8 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ const Container = div({
3434
const PrimaryButton = styled(Button)({
3535
color: 'red'
3636
})
37+
38+
// Component Selectors.
39+
const ButtonContainer = styled(Container)({
40+
[`& ${PrimaryButton}`]: {
41+
color: 'green'
42+
}
43+
})
3744
```
3845

3946
## Base Style Sheet

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"coveralls": "^3.0.0",
6060
"enzyme": "^3.1.0",
6161
"enzyme-adapter-react-16": "^1.0.1",
62+
"enzyme-to-json": "^3.1.2",
6263
"eslint": "^3.13.0",
6364
"eslint-config-airbnb": "^14.1.0",
6465
"eslint-config-jss": "^3.0.0",
@@ -92,6 +93,9 @@
9293
"coverageDirectory": "../coverage",
9394
"setupFiles": [
9495
"raf/polyfill"
96+
],
97+
"snapshotSerializers": [
98+
"enzyme-to-json/serializer"
9599
]
96100
}
97101
}

src/createStyled.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const createStyled = (jss: Function) => (baseStyles: BaseStylesType = {}): Style
4242
const {tagName, style} = getStyledArgs(tagNameOrStyledElement)
4343
const elementStyle = {...style, ...ownStyle}
4444

45-
return styled({tagName, baseStyles, elementStyle, mountSheet})
45+
return styled({tagName, baseStyles, elementStyle, mountSheet, jss})
4646
}
4747

4848
Object.defineProperty(styledWrapper, 'sheet', ({

src/styled.js

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,30 @@ import type {
1414
type StyledArgs = {
1515
tagName: string,
1616
elementStyle: ComponentStyleType,
17-
mountSheet: Function
17+
mountSheet: Function,
18+
jss: Function
1819
}
1920

20-
const styled = ({tagName, elementStyle, mountSheet}: StyledArgs) => {
21+
const styled = ({tagName, elementStyle, mountSheet, jss}: StyledArgs) => {
2122
const {dynamicStyle, staticStyle} = getSeparatedStyles(elementStyle)
2223
const staticTagName = staticStyle && generateTagName(tagName)
2324

2425
const availableDynamicTagNames = []
2526
const classMap = {}
2627

27-
return class StyledElement extends Component<StyledElementPropsType> {
28+
let staticClassName
29+
30+
class StyledElement extends Component<StyledElementPropsType> {
2831
static tagName: string = tagName
2932
static style: ComponentStyleType = elementStyle
3033

31-
dynamicTagName = ''
32-
33-
sheet: JssSheet
34-
3534
constructor(props: StyledElementPropsType) {
3635
super(props)
3736
if (!this.dynamicTagName && dynamicStyle) {
3837
this.dynamicTagName = availableDynamicTagNames.pop() || generateTagName(tagName)
3938
}
39+
40+
this.staticClassName = staticClassName
4041
}
4142

4243
componentWillMount() {
@@ -66,6 +67,10 @@ const styled = ({tagName, elementStyle, mountSheet}: StyledArgs) => {
6667
availableDynamicTagNames.push(this.dynamicTagName)
6768
}
6869

70+
dynamicTagName = ''
71+
sheet: JssSheet
72+
staticClassName = ''
73+
6974
updateSheet(props: StyledElementPropsType) {
7075
let rule
7176
let ruleIndex = 0
@@ -83,6 +88,7 @@ const styled = ({tagName, elementStyle, mountSheet}: StyledArgs) => {
8388

8489
const props = filterProps(tagName, attrs)
8590
const tagClass = composeClasses([
91+
this.staticClassName,
8692
staticTagName && this.sheet.classes[staticTagName],
8793
this.dynamicTagName && this.sheet.classes[this.dynamicTagName],
8894
className
@@ -91,6 +97,22 @@ const styled = ({tagName, elementStyle, mountSheet}: StyledArgs) => {
9197
return createElement(tagName, {...props, className: tagClass}, children)
9298
}
9399
}
100+
101+
// $FlowIgnore
102+
StyledElement.valueOf = () => {
103+
if (!staticClassName) {
104+
staticClassName = `.${jss.generateClassName({
105+
key: generateTagName('static')
106+
})}`
107+
}
108+
109+
return staticClassName
110+
}
111+
112+
// $FlowIgnore
113+
StyledElement.toString = StyledElement.valueOf
114+
115+
return StyledElement
94116
}
95117

96118
export default styled

src/tests/__snapshots__/functional.spec.jsx.snap

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,48 @@ exports[`functional tests should update props and unmount 2`] = `
100100
}"
101101
`;
102102

103+
exports[`functional tests should use Styled Component classname in string 1`] = `
104+
".div-4-id:not(:first-child) .static-2-id {
105+
display: none;
106+
}
107+
.div-4-id:not(:last-child) .static-3-id {
108+
visibility: hidden;
109+
}
110+
.div-4-id .static-2-id {
111+
color: green;
112+
}
113+
.div-1-id {
114+
color: red;
115+
}
116+
.img-5-id {
117+
width: 30px;
118+
}"
119+
`;
120+
121+
exports[`functional tests should use Styled Component classname in string 2`] = `
122+
<StyledElement>
123+
<div
124+
className="div-4-id"
125+
>
126+
<StyledElement>
127+
<div
128+
className=".static-2-id div-1-id"
129+
>
130+
name
131+
</div>
132+
</StyledElement>
133+
<StyledElement
134+
width={30}
135+
>
136+
<img
137+
className=".static-3-id img-5-id"
138+
width={30}
139+
/>
140+
</StyledElement>
141+
</div>
142+
</StyledElement>
143+
`;
144+
103145
exports[`functional tests should use props on remount 1`] = `
104146
".button-1-id {
105147
color: black;

src/tests/functional.spec.jsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,36 @@ describe('functional tests', () => {
134134

135135
wrapper.unmount()
136136
})
137+
138+
it('should use Styled Component classname in string', () => {
139+
const AuthorName = styled('div')({color: 'red'})
140+
const Avatar = styled('img')({width: props => props.width})
141+
142+
const Message = styled('div')({
143+
[`&:not(:first-child) ${AuthorName}`]: {
144+
display: 'none'
145+
},
146+
[`&:not(:last-child) ${Avatar}`]: {
147+
visibility: 'hidden'
148+
},
149+
[`& ${AuthorName}`]: {
150+
color: 'green'
151+
}
152+
})
153+
154+
const wrapper = mount(
155+
<Message>
156+
<AuthorName>name</AuthorName>
157+
<Avatar width={30} />
158+
</Message>
159+
)
160+
161+
const {sheet} = styled
162+
163+
assertSheet(sheet)
164+
165+
expect(wrapper).toMatchSnapshot()
166+
167+
wrapper.unmount()
168+
})
137169
})

yarn.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,12 @@ enzyme-adapter-utils@^1.0.0:
14331433
object.assign "^4.0.4"
14341434
prop-types "^15.5.10"
14351435

1436+
enzyme-to-json@^3.1.2:
1437+
version "3.1.2"
1438+
resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.1.2.tgz#7681e04c5747bb140c4c658ba7f07a6679e1f3b6"
1439+
dependencies:
1440+
lodash "^4.17.4"
1441+
14361442
enzyme@^3.1.0:
14371443
version "3.1.0"
14381444
resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.1.0.tgz#d8ca84085790fbcec6ed40badd14478faee4c25a"

0 commit comments

Comments
 (0)