LoginSignup
35
2

More than 1 year has passed since last update.

date pickerとdate range pickerができるまで

Last updated at Posted at 2022-11-30

この記事は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はこのようなものを作成しました。

date_picker1.gif

以下のような仕様をもとに作成されています。

  • インプットエリアは自由入力が可能
  • 不正な入力値はバリデーションされる
  • パネルによる日付選択が可能
  • パネルは年・月・日の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になっており、これらのスタイルを綺麗にすることにも苦労しました。

date_picker_2.png

inputのブラウザ標準のスタイルを上書きしたり、inputのカーソルの反応範囲を適切に設定するなど、細かな部分に気を使う実装が多く、面白かったです。
ちなみに、たとえば標準スタイルの上書きについては次のようなコードで実装すると、
sample_input.png
こういったinputができます。divposition: 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を導入すると、onBluronKeyDown等を設定する必要があります。
またdate pickerはパネルを有するのでonClickも設定する必要があり、パネルの入力とinputの入力を適切に処理しなければいけません。
これが意外と難しく、inputonBlurを素直に設定するとパネルでのonChangeが発火しなくなるというバグに直面しました。
理由は単純で、マウスイベントは下記の順に発火します。

onMouseDown → onBlur → onMouseUp → onClick

バグの原因は、inputonBlurを設定すると、パネルをonClickする前にonBlurが効いてパネルが消えてしまうことでした。
わかってみると単純なのですが、マウスイベントはコードだけ確認しても正しく機能しているか判断がつきにくく、個人的にはとても苦労しました。
またこれ以外にも、IMEの変換のためのEnter押下とインプットから離脱するEnter押下の判別など、イベント操作を監視する必要が多く学びになりました。

まとめ

アドベントカレンダー1日目ということで何を書くか迷ったのですが、今回はdate pickerとdate range pickerができるまで、試行錯誤をした内容を紹介しました。
実はdate pickerは入社してからはじめて自分がメインで実装を担当したコンポーネントだったのですが、
その当時から社内の先輩エンジニアやデザイナーの方が良い意味で自分をフラットなメンバーの一員として扱ってくださり、ありがたいなと感じていました。
ということで、そんな弊社に興味を持った方がいればぜひ下記ページからご応募ください!

35
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
2