日付選択機能が拡張しやすそうというで理由でblueprintというUI Toolkitを使っているのだが、実際に使ってみて見た目を変えたいなと思った所、結構癖があったのでメモしていく。
blueprintのDatePickerはReact-Day-Pickerのラッパー的なもの
blueprintのDatePickerはReact-Day-Pickerをベースにしていて、プロパティ経由で簡単にReact-Day-Pickerのプロパティを指定することができる。
ので、見た目を変えるときはReact-Day-Pickerの機能を使う必要が出てくる。
export function Test() {
const customProps = { ... } //React-Day-Pickerの設定
return <DatePicker dayPickerProps={customProps} />
}
スタイルを変えるときに取ることが出来る方法は以下のものがある。
ここで注意するのが、日にちに対するスタイルの指定とUI全体のスタイルの指定の二種類ある
(classNameも用意されている)
カレンダーの日にちのスタイルを変更する
- modifiers
- modifiersStyles
DayPicker全体のスタイルを変更する
- classNames
日にちのスタイルを変更する
React-Day-Pickerではある日にちをいじりたいときはmodifiersプロパティを使って指定する形をとっている。
その際グループ化したい日にちのパターンとその名前という形で設定していく。
設定したグループの日にちにはDayPicker-Day--<グループ名>
という名前のCSSクラスの名前が与えられるので
それに対してスタイルを設定すると好きな見た目に変更することが出来る。
もちろん自動生成されたCSSクラス名をCSSファイルに書かないといけない訳ではなく、modifiersStyles
にグループ名をキーをとしたinline-Styleを設定すればいい。
Matching days with modifiersにあるサンプルコードをちょっと変えたもの。
import React from 'react';
import DayPicker from 'react-day-picker';
import 'react-day-picker/lib/style.css';
const birthdayStyle = `.DayPicker-Day--highlighted {
background-color: orange;
color: white;
}`;
const modifiers = {
highlighted: new Date(2018, 8, 19),
};
const modifiersStyles = {
highlighted: {
color: '#FF0000'
}
}
export default function MyBirthday() {
return (
<div>
<style>{birthdayStyle}</style>
<DayPicker
modifiers={modifiers}
modifiersStyles={modifiersStyles}
month={new Date(2018, 8)} />
</div>
);
}
日にちの指定の仕方
グループを作る際の日にちの指定には以下の種類があるので適当に使い分ける。
グループは複数指定でき、ある日にちが二つ以上のグループにあるときはその全てが適応される。
- from/toキー この二つに与えたDateオブジェクトの範囲内の日にちをグループ化する
- beforeキー 与えた日にちより前のものをグループ化する
- afterキー 与えた日にちより後のものをグループ化する
- daysOfWeek 指定した曜日でグループ化する。曜日は0から6の範囲を取り、それぞれ日曜から土曜に対応している。配列で渡すと複数の曜日を指定できる。
- function(day: Date):boolean グループ化する日にちのときはtrueを返すDateオブジェクトを受け取る関数
const from_to = [
from: new Date(2018, 8, 19),
to: new Date(2018, 9, 19),
]
const before_after = {
after: new Date(2018, 9, 1),
before: new Date(2018, 10, 1)
}
const daysOfWeek = {
daysOfWeek: [0] // 日曜日
}
const func = (day) => { return day.getDate() % 2 === 0}
export default function Grouping() {
return (
<div>
<style>{birthdayStyle}</style>
<DayPicker
modifiers={[from_to, before_after, daysOfWeek]} />
</div>
);
}
用意されているグループ
ちなみにtodayとoutsideが予め用意されており、それぞれ今日の日にちと現在の月以外の日にちが対象になる。
イベントとの組み合わせ
グループはDayPickerのイベントが起きたときに日にちを識別する目的にも使うことが出来る。
グループ情報を参照することが出来るイベントにはmodifiersがオブジェクトとして引数に渡されていて、
そのオブジェクトには所属しているグループの名前をboolean型として持っている。
//ドキュメントから拝借
import 'react-day-picker/lib/style.css';
export default class EventHandlers extends React.Component {
constructor(props) {
super(props);
this.handleDayClick = this.handleDayClick.bind(this);
this.handleDayMouseEnter = this.handleDayMouseEnter.bind(this);
}
handleDayMouseEnter(day, { firstOfMonth }) {
if (firstOfMonth) {
// Do something when the first day of month has been mouse-entered
}
}
handleDayClick(day, { sunday, disabled }) {
if (sunday) {
window.alert('Sunday has been clicked');
}
if (disabled) {
window.alert('This day is disabled');
}
}
render() {
return (
<DayPicker
disabledDays={new Date()}
modifiers={{
sunday: day => day.getDay() === 0,
firstOfMonth: day => day.getDate() === 1,
}}
onDayClick={this.handleDayClick}
onDayMouseEnter={this.handleDayMouseEnter}
/>
);
}
}
と、かなり汎用性があるものになっている。
DayPicker全体のスタイルを変更するときはclassNames用のテンプレートを使おう
日にちについてはかなり柔軟なカスタマイズが出来るようになっているが、
それ以外の例えばヘッダー部分とかの背景色を変更したいときはclassNamesプロパティを使う。
classNamesにはDayPickerで使われる要素全てにCSSを指定する形になっている。
各要素には使用するCSSクラスを指定するのだが、要素の数は結構あるので公式から用意されているテンプレートを書き換えるのがいいと思う。
テンプレートはこちら react-day-picker/src/classNames.js
テンプレートのインターフェイスはimport {ClassNames} from 'react-day-picker'
からインポート出来る。
function makeClassNames(config) {
const DEFAULT = {
container: 'DayPicker',
wrapper: 'DayPicker-wrapper',
interactionDisabled: 'DayPicker--interactionDisabled',
months: 'DayPicker-Months',
month: 'DayPicker-Month',
navBar: 'DayPicker-NavBar',
navButtonPrev: 'DayPicker-NavButton DayPicker-NavButton--prev',
navButtonNext: 'DayPicker-NavButton DayPicker-NavButton--next',
navButtonInteractionDisabled: 'DayPicker-NavButton--interactionDisabled',
caption: 'DayPicker-Caption',
weekdays: 'DayPicker-Weekdays',
weekdaysRow: 'DayPicker-WeekdaysRow',
weekday: 'DayPicker-Weekday',
body: 'DayPicker-Body',
week: 'DayPicker-Week',
weekNumber: 'DayPicker-WeekNumber',
day: 'DayPicker-Day',
footer: 'DayPicker-Footer',
todayButton: 'DayPicker-TodayButton',
// default modifiers
today: 'today',
selected: 'selected',
disabled: 'disabled',
outside: 'outside',
};
return Object.assign({}, DEFAULT, config)
}
export default function CustomClassNames() {
//
const classNames = makeClassNames({
container: 'changeBackground'
})
return (
<DayPicker
classNames={ styles }
modifiers={{
[styles.birthday]: new Date(2018, 8, 19)
}}
/>
);
}
ちなみにデフォルトで設定されているクラスを完全に上書きしてしまうとレイアウトが崩れたので、次のように追記する形にしたほうがいいと思う。
指定したクラス名はそのまま設定されるようなので、classnames
パッケージとか利用したら便利。
const custom = {
caption: classnames('DayPicker-Caption', 'appendStyles')
}
もちろんCSSModuleも使える
ので、好きな方法でスタイルをカスタマイズすることが出来る。
かなり拡張性が高いパッケージになっていて、日時選択にはこれが一番融通がきくのではないかなと。
おすすめのパッケージです。