Skip to content

Instantly share code, notes, and snippets.

@maxsbelt
Last active October 23, 2020 17:36
Show Gist options
  • Save maxsbelt/6336fde9c66a4fad94789ff1e092f81f to your computer and use it in GitHub Desktop.
Save maxsbelt/6336fde9c66a4fad94789ff1e092f81f to your computer and use it in GitHub Desktop.
styled-components with namespaces
import styled from 'styled-components'
export * from 'styled-components'
const getNamespace = props => props.theme.namespace || ''
const isPure = args =>
(args.length === 1 && args[0] === '') ||
args.find(arg => arg === getNamespace)
const tag = method => (...args) => {
if (isPure(args)) return method(...args)
const [strings, ...restArgs] = args
return method(
['', ' & {', ...strings, '}'],
getNamespace,
'',
...restArgs,
''
)
}
const tagWithConfig = sc => {
const tagged = tag(sc)
tagged.withConfig = (...args) => tag(sc.withConfig(...args))
return tagged
}
const namespacify = sc => {
const result = tagWithConfig(sc)
result.attrs = (...args) => tagWithConfig(sc.attrs(...args))
return result
}
const styledns = component => namespacify(styled(component))
Object.keys(styled)
.filter(code => typeof styled[code] === 'function')
.forEach(code => {
styledns[code] = namespacify(styled[code])
})
styledns.ns = getNamespace
export default styledns
import styled, { css, keyframes } from 'styled-components'
const NAMESPACE = '#root'
const invoke = method => (styles, ...args) => {
const namespacedStyles = styles.length === 1
? [`${NAMESPACE} & { ${styles[0]} }`]
: [
`${NAMESPACE} & { ${styles[0]}`,
...styles.slice(1, -1),
`${styles[styles.length - 1]} }`,
]
return method(namespacedStyles, ...args)
}
const withNamespace = { ...styled }
Object.keys(styled).forEach(prop => {
if (typeof styled[prop] === 'function') {
withNamespace[prop] = invoke(styled[prop])
}
})
withNamespace.NAMESPACE = NAMESPACE
withNamespace.default = styled
export {
css,
keyframes,
}
export default withNamespace
import styled from './styled'
const Container = styled.div`
background: red;
@media (min-width: 1024px) {
background: green;
color: ${props => props.color};
font-size: ${props => props.fontSize};
}
`
const Container2 = styled.default.div`
${styled.NAMESPACE} & {
background: red;
@media (min-width: 1024px) {
background: green;
}
}
[dir='rlt'] ${styled.NAMESPACE} & {
background: blue;
}
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment