ingred-ui
ingred-ui copied to clipboard
DateRangePickerのリニューアル
背景
-
momentjs
とreact-dates
の置き換えをする過程で DateRangePicker そのものに不満があるという話が上がってきた - そもそも現状の DateRangePicker が急ごしらえのもので、理想形ではない
- なので理想形のDateRangePickerを作る方向ですすめることにした
デザイン
https://xd.adobe.com/view/a2977fa3-990f-4e0b-7eb7-1f835cc8c42a-d4a6/screen/baa54a33-a87a-4fa4-9fea-b8c26bac63e7/
- DatePickerもデザインはほぼ同じものを使う
関連issue
まずはデザインを見せてDstメンにユーザーヒアリングする たぶんDstメンがほしいっていうとみんなほしいと思うので
@maktak1995 とりあえずプロトタイプ作ったんだけど、XDの都合上うまく表現できない部分もあるんで口頭で説明しますね
プロトタイプの動作補足説明
キーボード入力
- 必要な桁数入力されたら自動で隣にフォーカスが移動する
- Enter押下でも同じ挙動
カレンダー入力
-
カレンダー左上に同様の入力欄
-
カレンダーは縦スクロール
-
スティッキーな日付表示はスクロールすると月が切り替わる
-
クリックすると各月へのショートカットが表示される
-
縦スクロールなのは一般的に横スクロールはしづらいものだから
仕様Doc: https://docs.google.com/document/d/1xCYGOcgtyQfXsAi0Tv_OW1XrdkyDqE8f2hBI87uRIbc/edit#
背景の整理
今回のタスクは複数のやりたいことが絡まっているのでそれを解きほぐした上でタスクをブレイクダウンしたい
momentjs を除去したい
- 公式がサポート終了するから
React-dates を除去したい
- momentjs に依存しているライブラリだから
- 更新が滞っており react v18 への対応が見込めないから
DateRangePicker のデザインをリニューアルしたい
- 現状のデザインは仮のもの
- ちゃんとしたデザイン案に沿ったものとしたい
目的
1. momentjs と react-dates を剥がす
- 現実的な候補として dayjs がある
- interface が momentjs と同じなので置換をやりやすい
- 様々なライブラリ候補のなかで一番小さい
- dayjs であれば react-dates の置換先として dayjs ネイティブなものではなくても momentjs 用のライブラリをfolkして置き換えて使うという選択肢も出てくる
- ステップ2を考慮したライブラリでまずはそのままの置換をすすめる?
2. DateRangePicker のデザインを変更する
- デザインと仕様はすでに固まっている
- いいライブラリがなければフルスクラッチもありうるが、難易度は跳ね上がる
- spectrum など参考になりそうな実装はある
muiのdateRangePickerがdayjs使っててUIがreact-datesと同じなので最初の置き換えにはいいかもしれない https://mui.com/x/react-date-pickers/date-range-picker/
最初のステップとしてmuiを使った置き換えを検討したが、muiのDateRangePickerは有料版限定のコンポーネントであった。 なのでアウト。
他の置き換え候補
react-suite DateRangePicker
- 更新が活発でReact v18への対応も進んでいる
- 中華製で他に比べると利用率は高くない
- デザインシステム全部をインストールする必要があるためバンドルの肥大化が懸念される
daterangepicker-dayjs
- momentjsを利用したdaterangepickerを個人でフォークしてdayjsに対応させたもの。
- jqueryを使用しておりレガシーな実装
- Reactでの利用は考慮されていない
- 更新が1年前で止まっている
momentjsを使っている他の開発が活発なDateRangePicker
- react-datesしか見つからなかった
date-fns だと react-date-range といういい感じのライブラリがある
案1: react-suite をインストールして使用する
- 活発なライブラリなので安定した利用が見込める
- ライブラリのコンポーネント全部インストールしないといけないのでバンドルが肥大化する
案2: react-date-range を使う
- かなり柔軟なライブラリなので今後来る新しいデザインにもそのまま使い回せるかも
- dayjsでもmomentjsでもないのでingred-uiを導入しているプロダクト側の大規模な対応が必要になる
案3: react-datesをfolkしてきてdayjsとReact18に対応できるよう改修して使う
- ぱっとコードを見た感じそこまで難しいことでもまあなさそう
- 完全に自分たちで管理することにはなる
- うまくいけばingred-ui側の変更を最小限にして置き換えることが可能になる
案3かなー 結局デザインは(いつ変えるかはわからないが) あとから変わるんだし、応急手当的な処理でもまあいいんじゃないか、という気はする
いろいろしてみたがやっぱりreact-datesの手直しは全体的に古くなってるせいで余計に難しく、現実的ではなかった date-fnsであれば使えるライブラリがいくつか存在しているので、移行先をdayjsからdate-fnsに変えられないか、変えた場合はどんな影響が出るのかを調査して可能そうであればdate-fnsに変える方向に倒したい。
@takurinton がdayjsでのカレンダー自作の検証をしてくれた。良さそうなので最終的にはdayjsでフルスクラッチする方針とする。 https://dev.takurinton.com/tech/frontend/calender-ui-prototype.html https://github.com/takurinton/calender/pull/2
最終的な実装方針は以下の通り。
- react-dates の moment.js の部分を dayjs に変換するラッパーを作る
- 一旦リリースして各プロダクト置き換え
- 置き換えてる間に新しいカレンダーをフルスクラッチ + dayjs で実装
- なんかこれ用のリリースブランチ(v11.0.0-beta-1 とか)作るか、コンポーネントの名前を
<DatePickerNext />
とかに変えて試験運用してみる - 良さそうだったらいよいよ置き換え
@maktak1995
どのように誰に引き継いだのかを書いておいてもらえると:pray:
上から順にやります。 それぞれのコンポーネントを export して、使う側で組み合わせることも可能な状態にする(実際、社内でそういうユースケースがありそうなので)
- [x] Calendar コンポーネントの追加 https://github.com/voyagegroup/ingred-ui/pull/1361
- [x] DateField コンポーネントの追加 https://github.com/voyagegroup/ingred-ui/pull/1362
- [x] DatePicker の追加 https://github.com/voyagegroup/ingred-ui/pull/1363
- [x] CalendarRange コンポーネントの追加 https://github.com/voyagegroup/ingred-ui/pull/1365
- [x] DateRangeField コンポーネントの追加 https://github.com/voyagegroup/ingred-ui/pull/1367
- [x] DateRangePicker コンポーネントの追加 https://github.com/voyagegroup/ingred-ui/pull/1369
- [x] スタイルの細かい修正
- [x] インターフェイスの整理 https://github.com/voyagegroup/ingred-ui/issues/975#issuecomment-1683372939
- [x] 年選択の実装 https://github.com/voyagegroup/ingred-ui/issues/975#issuecomment-1685744375
- [x] (リファクタ) https://github.com/voyagegroup/ingred-ui/pull/1372
snapshot テストは style やインターフェイス調整するタイミングで入れる(Calendar と DateField を組み合わせて DatePicker 作るし、その段階で都度更新するのは疲れるので)
ここまでやってきたこと
- issues
- https://github.com/voyagegroup/ingred-ui/issues/871
- https://github.com/voyagegroup/ingred-ui/issues/856
- prototype
- https://github.com/takurinton/dateinput
- https://github.com/takurinton/calendar (微調整ののち採用)
- https://github.com/takurinton/datepicker-integration
- https://github.com/takurinton/date (採用)
- memo
- https://memo.takur.in/tech/frontend/calender-ui-prototype.html
- https://memo.takur.in/tech/frontend/calender-ui-prototype-with-scroll.html
- https://memo.takur.in/tech/frontend/calender-ui-prototype-with-scroll-performance-improvement.html
- https://memo.takur.in/tech/frontend/dateinput-components.html
- https://memo.takur.in/tech/frontend/datefield.html
細かいデザインやドキュメントは社外向けに書いてないので一旦載せない。後で整理して出す。
DateRangeField について
現状だと format prop は1つしか渡すことができず、開始日と終了日に共通のフォオーマットを当てる形にしてるけど、それぞれ独立させたいケースがあるかもしれない。
例として、広告の配信期間を指定する際
- 開始日時は
HH時00分00秒
を指定したい - 終了日時は
HH時59分59秒
を指定したい
みたいなケースがありそうで、それを format で縛ろうとするとそれぞれ独立していた方がやりやすい
最悪、format に HH時mm分ss秒
と入れれば可能ではあるけど、分や秒はユーザーに触らせたくないみたいなのもそれなりに存在するという想定。
date prop に null を含めるかどうか検討したい。 ユースケースを見る限り、null を入れたいケースはありそう ~(例えば終了日時を指定せずに submit する時など)~ → null じゃなかった、ということは実質なさそう。
となると、インターフェイス的には
type Props = {
date: Dayjs
onDateChange: (newDate: Dayjs) => void
}
という感じになりそう。しかし、一般論的には null 許容しているライブラリが多いことを頭の片隅に入れておくべき(今回のケースだと、ingred-ui は社内用ライブラリなので社内でのユースケースに特化させても問題ない)
他の props の整理に関してはインターフェイスの整理をする PR で議論、相談する。
思慮が浅かった、dayjs 自体が null を返してくる可能性があるのか...。
既知のバグとしてこれがある https://github.com/voyagegroup/ingred-ui/pull/1367#pullrequestreview-1579729227
TODO カレンダーを閉じる用のバツボタンを実装していないのでする
追記
done https://github.com/voyagegroup/ingred-ui/pull/1370
DateRangePicker、Actions が多重定義されてる。 後で修正する。
追記
done https://github.com/voyagegroup/ingred-ui/pull/1371
インターフェイスの整理をする。 それぞれのコンポーネントに以下の props を追加する。
- DatePicker/DateRangePicker
- errorText #1377
- disable #1376
- isOutsideRange #1375
- Calendar/CalendarRange
- isOutsideRange #1375
- DateField/DateRangeField
- errorText #1377
- disable #1376
年選択のスクロールについてやる。 これは
- [x] カレンダーの無限スクロールを担っている useScroll を useScrollCalendar にリネーム https://github.com/voyagegroup/ingred-ui/pull/1384
- [x] 年選択の無限スクロールを担う useScrollYear を追加 https://github.com/voyagegroup/ingred-ui/pull/1385
- [ ] ~Intersection Observer API を扱う部分を抽象化した useIntersecion の定義~ → 一旦不要
という流れでやる。
年選択のスクロールの前に一旦リリースかけてもいいかもな。プロダクト側で使う期間が欲しい。 最低限のインターフェイスさえ揃えば問題なく使えるので(現在追加してるインターフェイスはプロダクト側のコードをベースに定義してるので特段困らないはず)
memo
errorText
prop の必要性とデザインを野呂さんに確認する。
https://github.com/voyagegroup/ingred-ui/pull/1377#issuecomment-1687238377
一旦リリースかける。 残タスクは以下。
-
errorText
prop の相談 → (追記)確認の結果、現行のまま行く - 年選択 → https://github.com/voyagegroup/ingred-ui/issues/975#issuecomment-1685744375 で対応
- スタイルの細かい修正 → https://github.com/voyagegroup/ingred-ui/pull/1395
ひとまず v14.5.0 リリース。 https://github.com/voyagegroup/ingred-ui/releases/tag/v14.5.0
今後の流れとしては、
- 14.6.0 → 残タスク(errorText の相談、style の修正(デザイナーレビュー)、年選択)の実装
- (追記) 14.7.0 → i18n 対応
- 15.0.0 → DatePicker を完全に新しいものにする
という形でやっていく。v14.6.0 と v15.0.0 の間で小さいバグであったり、運用上の不具合の修正はしていく。