この記事はHRBrain Advent Calendar 2022の1日目の記事です。
こんにちは。フロントエンドエンジニアの塚本です。
この記事では、date pickerとdate range pickerを作成するまでに行ったトライアンドエラーについてお話しようと思っています。
どうして作ったのか
date pickerやdate range pickerは実装コストが高く、そもそも標準のHTMLや外部ライブラリを使用するケースもあるかと思います。
弊社の場合はtoBeかつマルチプロダクトであることから、全プロダクト共通で標準UIよりもわかりやすいインターフェイスでなければならない等の都合があることや、
このようなdate pickerやdate range pickerをプロダクト内で使用する頻度が高いことから、
ユーザー体験に関わってくるため社内のコンポーネントライブラリの一部として自前実装することとなりました。
どんなものを作ったのか
たとえばdate range pickerはこのようなものを作成しました。
以下のような仕様をもとに作成されています。
- インプットエリアは自由入力が可能
- 不正な入力値はバリデーションされる
- パネルによる日付選択が可能
- パネルは年・月・日の3タイプ
- disabledにする期間を設定できる
大変だったこと
作成にあたってトライアンドエラーをした部分があったので、そちらについて下記に書きます。
1888年以前の日付はJSTと時差がある
テストデータを1234年5月6日にしていたら、タイムゾーンが見慣れないGMT+0918
になっていることに気が付きました。
日本標準時はGMT+0900
のはずなので、これは一体なんだろう…?となりました。
詳しくは下記ブログを参照していただければと思いますが、
GMT+0918
は東京の地方時で、標準時が施行される1888年以前の日時を扱う際は時差がGMT+0918
と解釈されてしまうようでした。
const testDate1 = new Date(1234, 4, 6)
const testDate2 = new Date(2022, 11, 1)
console.log(testDate1)
// Sat May 06 1234 00:00:00 GMT+0918(日本標準時)
console.log(testDate2)
// Thu Dec 01 2022 00:00:00 GMT+0900(日本標準時)
参考にさせて頂いたブログ
https://www.m3tech.blog/entry/timezone-091859
複数のinput
を1つの要素にまとめて使う
date range pickerはinput
を2個もっており、開始日と終了日をそれぞれ入力できます。
しかし、UIの見た目としては1つのinput
になっており、これらのスタイルを綺麗にすることにも苦労しました。
input
のブラウザ標準のスタイルを上書きしたり、input
のカーソルの反応範囲を適切に設定するなど、細かな部分に気を使う実装が多く、面白かったです。
ちなみに、たとえば標準スタイルの上書きについては次のようなコードで実装すると、
こういったinput
ができます。div
はposition: relative
であれば好きなスタイルを当てることができます。
<div class="input-wrapper">
<text>placeholder</text>
<input class="sample-input" type="date"/>
</div>
.input-wrapper {
display: flex;
position: relative;
align-items: center;
justify-content: start;
border-radius: 6px;
border: 1px solid;
height: 40px;
padding: 0px 12px;
background-color: white;
width: 124px;
}
.sample-input {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent;
border: none;
outline: none;
position: absolute;
bottom: 0;
left: 0;
top: 0;
opacity: 0;
}
最小値や最大値について
今回は許容する日付の範囲を指定することができる設計にしました。
たとえばアンケートの回答日時を選択させる場合は「今日以降の日付のみ選択できる」といったカスタマイズが可能です。
この際、基準の値を含めるのかといった仕様設定が難しかったです。
結局は、ユーザーの慣れ親しんでいる仕様であれば学習コストが少ないだろう、という考えのもと
HTML標準と仕様を合わせることになりました。
eventが難しい
input
を導入すると、onBlur
やonKeyDown
等を設定する必要があります。
またdate pickerはパネルを有するのでonClick
も設定する必要があり、パネルの入力とinput
の入力を適切に処理しなければいけません。
これが意外と難しく、input
のonBlur
を素直に設定するとパネルでのonChange
が発火しなくなるというバグに直面しました。
理由は単純で、マウスイベントは下記の順に発火します。
onMouseDown → onBlur → onMouseUp → onClick
バグの原因は、input
にonBlur
を設定すると、パネルをonClick
する前にonBlur
が効いてパネルが消えてしまうことでした。
わかってみると単純なのですが、マウスイベントはコードだけ確認しても正しく機能しているか判断がつきにくく、個人的にはとても苦労しました。
またこれ以外にも、IMEの変換のためのEnter押下とインプットから離脱するEnter押下の判別など、イベント操作を監視する必要が多く学びになりました。
まとめ
アドベントカレンダー1日目ということで何を書くか迷ったのですが、今回はdate pickerとdate range pickerができるまで、試行錯誤をした内容を紹介しました。
実はdate pickerは入社してからはじめて自分がメインで実装を担当したコンポーネントだったのですが、
その当時から社内の先輩エンジニアやデザイナーの方が良い意味で自分をフラットなメンバーの一員として扱ってくださり、ありがたいなと感じていました。
ということで、そんな弊社に興味を持った方がいればぜひ下記ページからご応募ください!