Created
April 26, 2021 13:46
-
-
Save agriffis/c6116280df1ea26e0f1fe2027f196513 to your computer and use it in GitHub Desktop.
Custom xstyled re-exports
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as R from 'ramda' | |
import scStyled from 'styled-components' | |
import * as xstyled from '@xstyled/styled-components' | |
import { | |
css, | |
defaultTheme, | |
Preflight, | |
style, | |
ThemeProvider, | |
useTheme, | |
} from '@xstyled/styled-components' | |
import {compose, space, typography} from '@xstyled/system' | |
//---------------------------------------------------------------------- | |
// system | |
//---------------------------------------------------------------------- | |
void ` | |
// xstyled v2 released | |
prop: 'ui', | |
themeGet: v => ({theme}) => typography({...theme.typography[v], theme}), | |
cssProperty: R.identity, | |
// xstyled v2 unreleased | |
prop: 'ui', | |
key: 'typography', | |
cssProperty: v => ({theme}) => typography({...v, theme}), | |
// xstyled v3 unreleased | |
prop: 'ui', | |
key: 'typography', | |
css: v => ({theme}) => typography({...v, theme}), | |
` | |
const ui = style({ | |
prop: 'ui', | |
themeGet: v => ({theme}) => typography({...theme.typography[v], theme}), | |
cssProperty: R.identity, | |
}) | |
const prose = style({ | |
prop: 'prose', | |
themeGet: v => ({theme}) => | |
compose(space, typography)({...theme.typography[v], theme}), | |
cssProperty: R.identity, | |
}) | |
const system = compose(ui, prose, xstyled.system) | |
const sys = props => ({theme}) => system({...props, theme}) | |
//---------------------------------------------------------------------- | |
// shouldForwardProp and attrs | |
//---------------------------------------------------------------------- | |
const systemSet = new Set(system.meta.props) | |
const shouldForwardProp = (prop, defaultValidatorFn, elementToBeCreated) => { | |
if (prop === 'as' || prop === 'theme') { | |
return false | |
} | |
if (typeof prop === 'string' && systemSet.has(prop)) { | |
return false | |
} | |
if (typeof elementToBeCreated === 'string') { | |
// We must test elementToBeCreated so we can pass through props for <x.div | |
// as={Component} />. However elementToBeCreated isn't available until | |
// styled-components 5.2.4 or 6, and in the meantime will be undefined. | |
// This means that HTML elements could get unwanted props, but ultimately | |
// this is a bug in the caller, because why are they passing unwanted | |
// props? | |
return defaultValidatorFn(prop) | |
} | |
return true | |
} | |
const partitionProps = R.curry((names, props) => | |
R.compose( | |
names.has | |
? R.compose( | |
R.map(ps => R.pick(ps, props)), | |
R.partition(p => names.has(p)), | |
R.keys, | |
) | |
: R.juxt([R.pick(names), R.omit(names)]), | |
// Drop undefined values to approximate the effect of destructuring, since | |
// this function stands in for destructuring in a component. | |
R.reject(R.identical(undefined)), | |
)(props), | |
) | |
const partitionSystemProps = partitionProps(systemSet) | |
// .attrs(data('size', 'variant')) | |
const hoistDataAttrs = names => props => ({ | |
// variant becomes data-variant, etc. | |
...R.zipObj( | |
R.map(s => `data-${s}`, names), | |
R.props(names, props), | |
), | |
// Remove the original props with {variant: undefined} | |
...R.fromPairs(R.map(name => [name], names)), | |
}) | |
const defaultAttrs = attrs => props => ({...attrs, ...props}) | |
//---------------------------------------------------------------------- | |
// styled | |
//---------------------------------------------------------------------- | |
const tags = Object.keys(scStyled) | |
const getCreateStyle = (baseCreateStyle, ...generators) => { | |
const createStyle = (...args) => | |
baseCreateStyle`${css(...args, ...generators)}` | |
const redo = nextCreateStyle => getCreateStyle(nextCreateStyle, ...generators) | |
createStyle.attrs = attrs => redo(baseCreateStyle.attrs(attrs)) | |
createStyle.withConfig = config => redo(baseCreateStyle.withConfig(config)) | |
return createStyle | |
} | |
const styled = (component, ...generators) => | |
getCreateStyle(scStyled(component), ...generators) | |
tags.forEach(key => { | |
styled[key] = styled(key, system).withConfig({shouldForwardProp}) | |
}) | |
//---------------------------------------------------------------------- | |
// x | |
//---------------------------------------------------------------------- | |
const x = {} | |
tags.forEach(key => { | |
x[key] = styled[key]`` | |
}) | |
//---------------------------------------------------------------------- | |
// theme getters | |
//---------------------------------------------------------------------- | |
const assert = (cond, ...rest) => { | |
console.assert(cond, ...rest) | |
return cond | |
} | |
const themeGetter = theme => (path, def) => { | |
if (typeof path === 'object' && typeof theme === 'string') { | |
;[path, theme] = [theme, path] | |
} | |
if ( | |
assert( | |
typeof path === 'string' && typeof theme === 'object', | |
`themeGetter called with ${typeof path}, ${typeof theme}`, | |
) | |
) { | |
const v = R.pipe( | |
R.path(path.split('.')), | |
R.when(R.identical(undefined), R.always(def)), | |
)(theme) | |
assert(v !== undefined, 'not found in theme:', path) | |
return v | |
} | |
} | |
const th = (path, def) => props => themeGetter(props?.theme)(path, def) | |
const useThemeGetter = prefix => { | |
const theme = useTheme() | |
return (path, def) => | |
themeGetter(theme)(prefix ? `${prefix}.${path}` : path, def) | |
} | |
//---------------------------------------------------------------------- | |
// exports | |
//---------------------------------------------------------------------- | |
export default styled | |
export { | |
css, | |
hoistDataAttrs, | |
defaultAttrs, | |
defaultTheme, | |
partitionProps, | |
partitionSystemProps, | |
Preflight, | |
shouldForwardProp, | |
sys, | |
system, | |
th, | |
themeGetter, | |
ThemeProvider, | |
useTheme, | |
useThemeGetter, | |
x, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment