Skip to content

Instantly share code, notes, and snippets.

@mbixby
Created April 26, 2017 14:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mbixby/5757d62192f0bb7a8de446ae06c91258 to your computer and use it in GitHub Desktop.
Save mbixby/5757d62192f0bb7a8de446ae06c91258 to your computer and use it in GitHub Desktop.
Extending Material UI styles
import { merge } from 'lodash'
// This module allows us to completely customize all of Material UI's JSS stylesheets
// to define our own theme.
//
// Note that you Material UI's JSS is often tied to application logic and you may
// deviate from the official Material UI spec.
//
// Unlike using the `overrides` feature of jss-theme-reactor, here you have access to
// the original calculated styles and theme. Notably you can do deep merge (lodash.merge)
// with the original styles.
export default {
MuiText: (styles, theme) => merge(styles, {
subheading: {
textTransform: 'uppercase',
fontSize: 14,
fontWeight: theme.typography.fontWeightMedium,
letterSpacing: '0.05em',
marginBottom: '1em',
marginTop: '1em'
}
}),
MuiList: styles => merge(styles, {
root: {
WebkitOverflowScrolling: 'touch',
}
}),
MuiFormLabel: (styles, theme) => merge(styles, {
error: {
color: theme.palette.text.primary
},
focused: {
color: theme.palette.text.primary
}
}),
// ...
}
import MuiThemeProvider, { MUI_SHEET_ORDER } from 'material-ui/styles/MuiThemeProvider'
import jssGlobal from 'jss-global'
import { createStyleSheet } from 'jss-theme-reactor'
import { find, get, includes, forEach } from 'lodash'
import { createTheme } from './theme'
import materialUIStyles from './materialUIStyles'
// By default, jss-theme-reactor will compute Material UI stylesheet class names
// in format '[stylesheetName]-[className]-[hash]' (e.g. '.MuiButton-root-ca32cd').
// Because stylesheets registered with the jss-theme-reactor have unique names,
// we can drop the hash. This way we can easily override any CSS rules with JSS.
//
// Use at your own risk.
//
// Example:
// ```
// const jssStyles = {
// root: {
// // This will override styles of all material-ui's <Text /> components
// // under `.root`
// '& .MuiText-text': {
// color: 'white'
// }
//
// // Without this extension we would have to write something like the following:
// '& .MuiText-text-2eff32': {
// color: 'white'
// }
// }
// }
// ```
const muiStylesheetNames = [...MUI_SHEET_ORDER, 'MuiFormControl', 'MuiInput', 'MuiInputLabel']
export const overrideJssClassNameGeneration = (styleManager) => {
const origGenerateClassName = styleManager.jss.options.generateClassName
/* eslint-disable no-param-reassign */
styleManager.jss.options.generateClassName = function generateClassName(...args) {
const rule = args[1]
const sheetName = get(rule, 'options.sheet.options.name')
const hashedStr = origGenerateClassName(...args)
if (includes(muiStylesheetNames, sheetName) && rule.name) {
return `${sheetName}-${rule.name}`
}
else {
return hashedStr
}
}
/* eslint-enable */
}
const { styleManager, theme } = MuiThemeProvider.createDefaultContext({
theme: createTheme()
})
overrideJssClassNameGeneration(styleManager)
styleManager.jss.use(jssGlobal())
// Rendering a stylesheet here ensures that all of MUI's styleManager's stylesheets
// will be rendered *before* any other custom app JSS styles. This way any styles defined
// per component will take precedence over any MUI styles
styleManager.render(createStyleSheet('_Prioritized_', () => ({})))
const extendingStyleSheets = []
// TODO Clean up
// @param {String} name
// @param {(rules, theme) -> rules} callback
export const extendStylesheet = (name, callback) =>
extendingStyleSheets.push({ name, createRules: callback })
// TODO Clean up
forEach(materialUIStyles, (callback, name) =>
extendStylesheet(name, callback)
)
// Override styleManager.render to implement `extendStylesheet`
const origRender = styleManager.render
styleManager.render = (styleSheet) => {
const { name, createRules, options } = styleSheet
const extendingStyleSheet = find(extendingStyleSheets, { name })
if (extendingStyleSheet) {
const createExtendedRules = () => {
const rules = createRules(theme)
return extendingStyleSheet.createRules(rules, theme)
}
return origRender({ name, createRules: createExtendedRules, options })
}
else {
return origRender(styleSheet)
}
}
export { MuiThemeProvider, styleManager, theme }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment