Last active
August 12, 2016 17:10
-
-
Save rohozhnikoff/df2e26dbabe2cd67d54030f0b5549734 to your computer and use it in GitHub Desktop.
[react-native] style creator
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 { Platform, StyleSheet } from 'react-native'; | |
function prepareStyles(stylesheet) { | |
return StyleSheet.create( | |
mapValues( | |
stylesheet, | |
function wrapPlatformSpecificRules(rules) { | |
rules['ios'] && rules['ios'] = Platform.select({'ios': rules['ios']}); | |
rules['android'] && rules['android'] = Platform.select({'android': rules['android']}) | |
return rules; | |
} | |
) | |
) | |
} | |
function filterTrueSelectors(hash) { | |
return reduce(hash, (list, v, k) => { | |
v && list.concat([k]); | |
return list | |
}, []); | |
} | |
function makeKeyFromArguments(args) { | |
return map(args, function(v, k){ | |
ifObject(v) | |
? map(v, (v, k) => k + ':' + Boolean(v)).join(',') | |
: v; | |
}).join(';') | |
} | |
const Styler = function(){ | |
return Styler.create.apply(Styler, arguments); | |
} | |
Styler.utils = {} | |
Styler.theme = {} | |
const STORE = [] | |
Styler.create = function(rules){ | |
const id = STORE.length; // next available id | |
function getter(){ | |
if(arguments.length === 1 && isString(arguments[0])) { | |
return this[arguments[0]] | |
} | |
const key = makeKeyFromArguments(arguments); | |
return this[key] || this[key] = toArray(arguments).map((selector) => { | |
return isObject(selector) | |
? StyleSheet.flatten(filterTrueSelectors(selector).map((v, _selector) => this[s])) | |
: this[selector] | |
}) | |
} | |
const preparedRules = isFunction(rules) | |
? rules(this.utils, this.theme) | |
: rules | |
assign(getter, preparedRules); | |
if (isFunction(rules)) { | |
STORE[id] = { | |
getter, | |
rulesMethod: rules, | |
rulesKeys: keys(preparedRules) | |
}; | |
} | |
return getter; | |
} | |
Styler.extendTheme = function(theme){ | |
this.theme = isFunction(theme) ? theme(this.utils, this.theme) : theme; | |
Styler.recalc() | |
return this; | |
} | |
Styler.extendUtils = function(utils){ | |
this.utils = isFunction(utils) ? utils(this.utils, this.theme) : utils; | |
Styler.recalc(); // does it really need? maybe we separate dimensions/os to Params | |
return this; | |
} | |
Styler.recalc = function(){ | |
if(STORE.length === 0) { | |
return | |
} | |
STORE.forEach((handle) => { | |
const {getter, rulesMethod, rulesKeys} = handle; | |
const newRules = rulesMethod(this.utils, this.theme); | |
const nulledRules = rulesKeys.filter((key) => !newRules[key]) | |
.reduce((nulled, key) => { | |
nulled[key] = null | |
return nulled | |
}, {}); | |
handle.rulesKeys = keys(newRules) | |
assign(getter, nulledRules, newRules) | |
}); | |
Styler.bindedComponents.forEach((component) => { | |
component.forceUpdate() | |
}) | |
} | |
Styler.bindedComponents = []; | |
Styler.updateOnRecalc = function(RootComponent) { | |
Styler.bindedComponents.push(RootComponent) | |
return RootComponent | |
} | |
const STYLES = Styler.create(({rgba, size, orientation}, {basicFont}) => { | |
'wrapper': { | |
fontSize: basicFont + 1, | |
android: { | |
color: 'green' | |
}, | |
ios: { | |
color: 'blue' | |
} | |
}, | |
'wrapper-loading': { | |
background: rgba('#ff00ff', .5) | |
}, | |
'image': { | |
} | |
}) | |
class Component extends React.Component { | |
@Styler.updateOnRecalc // recalc all method-based styles, then force update | |
render() { | |
return <View style={[this.props.style, STYLES('wrapper', { | |
'wrapper-loading': this.props.isLoading | |
})]}> | |
<Image source={this.props.source} style={STYLES.image}/> | |
</View> | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment