前回は組み込みコンポーネントをMaterial-UIのコンポーネントに置き換え、簡単なスタイルを適用しました。
今回はuseStyle
にプロパティを渡して、プロパティごとに表示を切り替えます。
★前回の記事
今回の変更点
- 日曜日と土曜日の日付をそれぞれ赤色、青色にする
- 表示対象でない月の日付は薄い色にする
- 今日の日付を目立たせる
デモ : date-fns calendar
なお、ブログ主はデザインセンスがないので、その辺はご容赦ください。
プロパティの値によってスタイルを変化させる
今回のカレンダーでは、以下のように平日か土曜日か日曜日か、および表示対象の月かどうかで文字の色を変更します。
表示対象の月の日 | 前後の月の日 | |
---|---|---|
平日 | 黒 | グレー |
土曜日 | 青 | 薄い青 |
日曜日 | 赤 | 薄い赤 |
Adapting based on props のページを参考に、propsの値によってスタイルを変更します。
CalendarTableCell
というカスタムコンポーネントを追加し、TableCell
を置き換えます。
CalendarTableCell
には、曜日を表すwday
と、表示対象の月かどうかを表すisTargetMonth
を渡します。表示対象の月かを判定するには、date-fnsのisSameMonthを使用します。
CalendarTableCell
では、props
をuseCalendarCellStyles
に渡し、classes
を得ます。
useCalendarCellStyles
のcolor
の値に関数を指定し、props
を受け取れるようにします。
color
に指定した関数の中では、props
からwday
とisTargetMonth
を受け取り、その値によって色を返します。
import React, { useState } from 'react' // 中略 // 追加ここから import isSameMonth from 'date-fns/isSameMonth' import blue from '@material-ui/core/colors/blue' import red from '@material-ui/core/colors/red' // 追加ここまで // 中略 // 追加ここから const useCalendarCellStyles = makeStyles(theme => ({ calendarCell: { color: ({wday, isTargetMonth}) => { if(isTargetMonth) { switch(wday) { case 0: // Sunday return red[500] case 6: // Saturday return blue[500] default: return theme.palette.text.primary } } else { // previous or next month switch(wday) { case 0: // Sunday return red[200] case 6: // Saturday return blue[200] default: return theme.palette.text.secondary } } }, }, })) function CalendarTableCell(props) { const {wday, isTargetMonth, children, ...other} = props const classes = useCalendarCellStyles(props) return (<TableCell className={classes.calendarCell} {...other}>{children}</TableCell>) } // 追加ここまで function App() { const [targetDate, setTargetDate] = useState(new Date()) const classes = useStyles() const calendar = getCalendarArray(targetDate) return ( <div> <CssBaseline /> <Paper className={classes.paper}> <Grid container justify="space-between"> {/* 中略 */} </Grid> <Typography variant="h4" align="center" className={classes.yearmonth}>{format(targetDate, 'y年M月')}</Typography> <Table> <TableHead> {/* 中略 */} </TableHead> <TableBody> {calendar.map((weekRow, rowNum) => ( <TableRow key={rowNum}> {weekRow.map(date => ( {/* 変更ここから */} <CalendarTableCell key={getDay(date)} wday={getDay(date)} isTargetMonth={isSameMonth(date, targetDate)} align="center"> {getDate(date)} </CalendarTableCell> {/* 変更ここまで */} ))} </TableRow> ))} </TableBody> </Table> </Paper> </div> ) } export default App
実行結果です。表示対象の月とそれ以外、また曜日でも文字の色が変わりました。
今日の日付を目立たせる
最後に、今日の日付を目立たせます。今回はは背景色を変えます。 表示している日付が今日かどうかはdate-fnsのisSameDayを利用します。
import React, { useState } from 'react' // 中略 // 追加ここから import isSameDay from 'date-fns/isSameDay' import pink from '@material-ui/core/colors/pink' // 追加ここまで // 中略 const useCalendarCellStyles = makeStyles(theme => ({ calendarCell: { color: ({wday, isTargetMonth}) => { // 中略 }, // 追加ここから backgroundColor: ({isToday}) => isToday ? pink[50] : "transparent" // 追加ここまで }, })); function CalendarTableCell(props) { // isTodayを追加 const {wday, isTargetMonth, isToday, children, ...other} = props const classes = useCalendarCellStyles(props) return (<TableCell className={classes.calendarCell} {...other}>{children}</TableCell>) } function App() { const [targetDate, setTargetDate] = useState(new Date()) const classes = useStyles() const calendar = getCalendarArray(targetDate) const today = new Date() // 追加 return ( <div> <CssBaseline /> <Paper className={classes.paper}> <Grid container justify="space-between"> {/* 中略 */} </Grid> <Typography variant="h4" align="center" className={classes.yearmonth}>{format(targetDate, 'y年M月')}</Typography> <Table> <TableHead> {/* 中略 */} </TableHead> <TableBody> {calendar.map((weekRow, rowNum) => ( <TableRow key={rowNum}> {weekRow.map(date => ( {/* isToday={isSameDay(date, today)} を追加 */} <CalendarTableCell key={getDay(date)} wday={getDay(date)} isTargetMonth={isSameMonth(date, targetDate)} isToday={isSameDay(date, today)} align="center"> {getDate(date)} </CalendarTableCell> ))} </TableRow> ))} </TableBody> </Table> </Paper> </div> ) } export default App
実行結果です。今日の日付の背景色が変わりました。
ソースコード
ここまでのソースコードです。
GitHub - yucatio/date-fns-calendar at 3bebfa7d00b30156676517c1be7879c08b0022ee
環境
- npm: 6.12.1
- react: 16.12.0
- date-fns: 2.8.1
- Material-UI: 4.8.0
あとがき
簡単なカレンダー機能なのでブログの1記事になるかと思いましたがまさかの4記事になりました。
date-fns, react-hooks, Material-UIのmakeStylesと比較的新しめの機能に触れるいい機会になりました。
date-fnsは今回カレンダーを作成するのに必要な機能がほぼ盛り込まれていて大変便利だと感じました。
Material-UIのカスタムスタイルの使用には、今までwithStyles
を使用してきましたが、useStyle
の方がすっきり書けて良いと思いました。