@asphalt-react/theme-provider
Version:
Theme provider for Asphalt React
14 lines (8 loc) • 2.04 kB
JavaScript
;
var React = require('react');
var PropTypes = require('prop-types');
var asphaltWebTokens = require('@gojek/asphalt-web-tokens');
const MOBILE="mobile";const DESKTOP="desktop";const BREAKPOINT_S=599;const BREAKPOINT_L=1280;
const HASH_PREFIX="sphlt-tkns-";function stableHash(str){let hash=5381;for(let i=0;i<str.length;i+=1){hash=hash*33^str.charCodeAt(i);}return (hash>>>0).toString(36)}function generateHash({theme}){const serialized=stableHash(JSON.stringify(theme));const hash=HASH_PREFIX+serialized.toLowerCase().replace(/[^a-z0-9]/gu,"");return hash}function generateThemeStyles({theme,hash,wrap,responsive}){const toVars=obj=>Object.entries(obj).filter(([k])=>k!==MOBILE&&k!==DESKTOP).map(([k,v])=>` ${k}: ${v};`).join("\n");const selector=wrap?`.${hash}`:":root";const createMediaBlock=(query,styles)=>styles?`\n\n @media ${query} {\n${styles}\n }`:"";let mediaBlock="";if(responsive){if(theme.mobile){mediaBlock=createMediaBlock(`(max-width: ${BREAKPOINT_S}px)`,toVars(theme.mobile));}else if(theme.desktop){mediaBlock=createMediaBlock(`(min-width: ${BREAKPOINT_L}px)`,toVars(theme.desktop));}}return `${selector} {\n${toVars(theme)}${mediaBlock}\n}`}
const ThemeProvider=({theme=null,children,as:Tag="div",wrap=true,responsive=false})=>{const defaultTheme=responsive?{mobile:asphaltWebTokens.variables?.mobile}:asphaltWebTokens.legacyVariables;const activeTheme=theme??defaultTheme;const hash=generateHash({theme:activeTheme});const styleCss=React.useMemo(()=>{return generateThemeStyles({theme:activeTheme,hash,wrap,responsive})},[activeTheme,hash,wrap,responsive]);return React.createElement(React.Fragment,null,React.createElement("style",{blocking:"render"},styleCss),wrap?React.createElement(Tag,{className:hash},children):children)};ThemeProvider.propTypes={children:PropTypes.node.isRequired,theme:PropTypes.object,as:PropTypes.elementType,wrap:PropTypes.bool,responsive:PropTypes.bool};ThemeProvider.defaultProps={theme:null,as:"div",wrap:true,responsive:false};
exports.ThemeProvider = ThemeProvider;