UNPKG

@asphalt-react/theme-provider

Version:

Theme provider for Asphalt React

11 lines (7 loc) 2.33 kB
'use strict'; var React = require('react'); var PropTypes = require('prop-types'); var asphaltWebTokens = require('@gojek/asphalt-web-tokens'); var helper = require('@asphalt-react/helper'); const createHash=async themeStr=>{if(!themeStr)return null;return (await helper.hashUtil.hash(themeStr)).substr(0,8)};const WARN_MSG="ThemeProvider: Failed to apply theme.";class ThemeProvider extends React.Component{constructor(props){super(props);this.state={hash:null};if(props.theme){createHash(JSON.stringify(props.theme)).then(hash=>{this.setState({hash},this.mountStyles);}).catch(err=>{if(err){console.warn(WARN_MSG);}});}this.createStyleSheet=this.createStyleSheet.bind(this);this.generateWrapperClass=this.generateWrapperClass.bind(this);}componentWillUnmount(){this.unMountStyles();}componentDidUpdate({theme}){if(!this.props.theme)return;const prevThemeStr=JSON.stringify(theme);const newThemeStr=JSON.stringify(this.props.theme);if(prevThemeStr===newThemeStr)return;createHash(newThemeStr).then(hash=>{this.setState({hash},()=>{this.unMountStyles();this.mountStyles();});}).catch(err=>{if(err){console.warn(WARN_MSG);}});}mountStyles(){const sheet=this.createStyleSheet();const selector=`.${this.generateWrapperClass()}`;sheet.insertRule(this.createRule(selector,this.props.theme),0);}generateWrapperClass(){return `asphalt-theme-${this.state.hash}`}unMountStyles(){const styleNode=document.querySelector(`#asphalt-tokens-${this.state.hash}`);if(styleNode){styleNode.remove();}}createStyleSheet(){const styleNode=document.createElement("style");styleNode.type="text/css";styleNode.rel="stylesheet";styleNode.id=`asphalt-tokens-${this.state.hash}`;document.head.appendChild(styleNode);return styleNode.sheet}createRule(selector,variables){return `${selector} { ${this.createTokens(variables)} }`}createTokens(variables){return Object.keys(variables).map(key=>`${key}: ${variables[key]};`).join("")}render(){const{theme=asphaltWebTokens.legacyVariables,children,as:Tag="div"}=this.props;return theme?React.createElement(Tag,{className:this.generateWrapperClass()},this.props.children):children}}ThemeProvider.propTypes={children:PropTypes.node.isRequired,theme:PropTypes.object,as:PropTypes.elementType};ThemeProvider.defaultProps={theme:asphaltWebTokens.legacyVariables,as:"div"}; exports.ThemeProvider = ThemeProvider;