Material-UI - Style
MuiThemeProvider
Material-UIにはMuiThemeProvider
という関数が存在しており,
これがReact-ContextとwithStylesを通して全てのComponentのスタイルに影響している.
ここでは,
Material-UIのStyleに関してまとめる.
Material-UI
React Components that Implement Google's Material Design.
![2017-05-09 6.04.53.png](/images/2017/05/スクリーンショット 2017-05-09 6.04.53.png)
Package
- mateiral-ui@1.0.0-alpha.12
- react@15.5.3
- react-dom@15.5.3
Docs
$ git clone -b next git@github.com:callemall/material-ui.git
$ cd material-ui
$ yarn
$ cd docs yarn
$ yarn start
MuiThemeProvider
material-uiはMuiThemeProvider
関数を用いて,
全てのComponentのスタイルを管理する.
具体的には,
theme
とstyleManager
をpropsとしたMuiThemeProvider
関数を上層で使用する.
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
function App () {
return (
<MuiThemeProvider theme={theme} styleManager={styleManager}>
<Layout/>
</MuiThemeProvider>
)
}
render(<App/>, document.querySelector('#app'))
theme
とstyleManager
が存在しない場合はデフォルトのスタイルが適用される.
context
MuiThemeProvider
はReact-contextを用いていて,
componentのスタイルはこのcontextから動的に生成される.
class MuiThemeProvider extends Component {
static childContextTypes = {
styleManager: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
}
getChildContext () {
const { theme, styleManager } = this
return {
theme,
styleManager
}
}
}
この2つのコンテキストは必須であり,
propsが存在しない場合はcontextが生成されることになる.
class MuiThemeProvider extends Component {
static createDefaultContext(props = {}) {
const theme = props.theme || createMuiTheme();
const styleManager = props.styleManager || createStyleManager({
theme,
jss: create(jssPreset()),
});
if (!styleManager.sheetOrder) {
styleManager.setSheetOrder(MUI_SHEET_ORDER);
}
return { theme, styleManager };
}
}
theme
theme
はcreateMuiTheme
関数を用いて生成される.
このcreateMuiTheme
の引数に設定される{palette}
はcreatePalette
関数を用いて生成できる.
import { createMuiTheme } from 'material-ui/styles'
import { blue, pink } from 'material-ui/styles/colors'
import createPalette from 'material-ui/styles/palette'
const dark = true
const palette = createPalette({
primary: blue,
accent: pink,
type: dark ? 'dark' : 'light',
});
const theme = createMuiTheme({ palette })
このblue
などはObjectになっていて,
Material Design GuidelinesのColor paletteと一致している.
const blue = {
50: '#e3f2fd',
100: '#bbdefb',
200: '#90caf9',
300: '#64b5f6',
400: '#42a5f5',
500: '#2196f3',
600: '#1e88e5',
700: '#1976d2',
800: '#1565c0',
900: '#0d47a1',
A100: '#82b1ff',
A200: '#448aff',
A400: '#2979ff',
A700: '#2962ff',
contrastDefaultColor: 'light'
}
material-ui@0.18.0では多くのカラーコードを指定する必要があり微調整が面倒だったけど,
@1.0.0ではtype
などの値で動的にカラーコードが設定される.
createMuiTheme
createMuiTheme
にはpalette
以外にtransitions
などが含まれている.
function createMuiTheme(options = {}) {
const {
palette = createPalette(),
breakpoints = createBreakpoints(),
mixins = createMixins(breakpoints, spacing),
typography = createTypography(palette),
...more
} = options
return {
direction: 'ltr',
palette,
typography,
shadows,
transitions,
mixins,
spacing,
breakpoints,
zIndex,
...more
}
}
例えばtransitions
はtheme.transitions.create('transform', {})
などのように,
トランジション前とトランジション後のclassNameを生成してくれる.
トランジションさせたいときは,
これをthis.state
などで切り替えて使用する.
styleManager
styleManager
はtheme
の更新ができる.
const themeContext = MuiThemeProvider.createDefaultContext({ theme })
const styleManager = themeContext.styleManager
また,
theme
を動的に修正したい場合はstyleManager.updateTheme
関数を用いる.
styleManager.updateTheme(theme)
createStyleSheet
createStyleSheet
関数はStyleを生成しHtml内に展開してくれる.
変数styleSheet
には関連付けされたClassNameのオブジェクトが返される.
import { createStyleSheet, withStyles } from 'material-ui/styles'
const styleSheet = createStyleSheet('Example', (theme) => {
return {
paper: {
backgroundColor: theme.palette.background.paper,
maxWidth: 400
},
expand: {
transform: 'rotate(0deg)',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest
})
},
}
})
class Example extends Component{
render () {}
}
export default withStyles(styleSheet)(Example)
material-ui@0.18.0ではinline-styleだったので,
Jsxの時点では吐き出されるDOMとstyle属性が把握しづらかった.
![2017-05-09 9.17.00.png](/images/2017/05/スクリーンショット 2017-05-09 9.17.00.png)
@1.0.0からはjss-theme-reactorを用いて,
classNameを生成してComponentsのスタイルを管理することになったのでとても読みやすい.
また,
一般的な乱数からclassNameを生成するタイプではなく,
createStyleSheet(Example, theme => {})
のように名前を指定できる.
![2017-05-09 9.16.10.png](/images/2017/05/スクリーンショット 2017-05-09 9.16.10.png)
withStyles
withStyles
関数はcreateStyleSheet
関数が生成するオブジェクトをReact Componentにpropsとして渡してくれる.
class Example {
render () {
return <div className={this.props.classes.expand}></div>
}
}
export default withStyles(styleSheet)(Example)
Css-in-Jsでは名前空間の衝突が無いだけでなくStyleをオブジェクトとして管理できるので,
共有化がとても容易になる.
const cardStyle = {}
const paperStyle = {}
const styleSheet = createStyleSheet('Example', (theme) => ({
...cardStyle,
...paperStyle,
expand: {}
}))
classnames
classNames
を使うと複数classNameの管理が楽になる
material-uiのComponentではこれが使われている.
import classNames from 'classnames'
変数theme
からはcreatePalette
で生成したオブジェクトが扱える.
例えば,
true/falseでトランジションさせたいとき以下のようにStyleを生成する.
const styleSheet = createStyleSheet('Example', (theme) => ({
expand: {
transform: 'rotate(0deg)',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
},
expandOpen: {
transform: 'rotate(180deg)',
}
}))
この場合はexpand
は常にStyleとして存在し,
trueの時だけexpandOpen
が付加されトランジションする仕組み.
classnames
を用いて以下のように表現することができる.
class Example extends Component {
render () {
return <IconButton
className={classnames(classes.expand, {
[classes.expandOpen]: this.state.expanded,
})}
onClick={this.handleExpandClick}>
}
}