AI にカレンダー予約を作らせてみた — 日付は複雑系の本丸(やってみた #11)
/booking375px のビューポートで撮影。縦長のページはフレーム内をスクロールします。
解説記事
AI にカレンダー予約を作らせてみた — 日付は複雑系の本丸(やってみた #11)
やってみたシリーズ: 自作のデザインシステム
@gunjo/ui(群青)を、文脈ゼロの cold な AI に実 UI で作らせる連載。複雑系3本目、今回は カレンダー予約。
条件は同じ(出荷物そのもの+docs だけ、ソース非公開)。お題は /booking に、日付選択(過去日・満席日を無効)、時間スロット、サービス選択、氏名/メール、確定するとサマリーに反映。日付・時刻まわりは hydration やロケールの罠が多い複雑系。
結果 — 4/5
npm run build 成功、static prerender、コンソールエラー0。
気持ちいい発見: Calendar がデフォルトで日本語(日月火水木金土・2026年6月・日本の祝日)。英語アプリなら locale={enUS} を渡すだけ。「AIが使える日本語のデザインシステム」を名乗ってるので、これは狙いどおり——カレンダーが最初から日本語で出るのは、地味だけど効く。
さらに Calendar の getDisabledReason が秀逸: 無効日にホバー/フォーカスすると理由ツールチップ(「この日は過ぎています」等)が出て、しかもセルの aria-label にも入る(a11y)。Tooltip は self-wrap で provider 不要(#52 again)。TimePicker/Select はネイティブ <select> ベースで SSR-safe。
粗さ — 日付の複雑系が出した穴
① DatePicker が個別日付を無効化できない
予約で一番欲しい「過去日を無効+一部の日を満席で無効」が、DatePicker では表現できない。disabled がコンポーネント全体の boolean だけで、内部 Calendar に日付 matcher を渡せない(Calendar 単体は disabled: Matcher[] を受けるのに)。cold AI は DatePicker を諦めて raw Calendar に降りた。予約系の最頻ユースケースで主役が使えないのは痛い。→ #64
② 日付の hydration トラップ(ライブラリにヘルパー無し)
「過去日を無効」は new Date() に依存するので、render 中に素朴に計算するとSSR と client でカレンダーがズレる古典的な hydration mismatch。cold AI は today を useEffect でクライアント側だけで解決し、それまでプレースホルダを出して回避した。ライブラリはこの罠のヘルパーを何も出さない——複雑系で繰り返し出る落とし穴なので、docs か helper が欲しい。
③ docs のコード例が fetch に映らない(既出 #50)
今回も。採用者は同梱 TS 型で制御パターンを学んだ。
学び
複雑系は毎回、単純画面では出ない穴を出す。#9 はライブラリの空白(DnD 無し)、#10 は半完成(FileUploader)、#11 は API の不足(DatePicker が肝心の制御を通さない)と、日付特有の hydration 罠。
でも#11 は良い面も濃かった——日本語デフォルトとa11y ツールチップは、複雑系を通したからこそ「ちゃんと出来てる」と確認できた部分。盛らず、穴も良さも両方そのままスコアボードに。まだ枯れない。
次回予告(やってみた #12)
- Chat インターフェース(ChatInput / メッセージ列)— もう一つの複雑系。
試す
- gunjo.jp / npm
@gunjo/ui/ GitHub - 前回まで: #1〜#10
- 母艦: 群青(@gunjo/ui) / なぜ要るのか: AI 時代のデザインシステム論
- GunjoUI by UIXHERO
まだ alpha、でも日本語で青になりつつある。複雑系ほど、穴も良さも正直に出る。
<!-- 公開前: #64 反映後に記述更新/スクショ確定/相互URL差込/EN(dev.to)ミラー -->
使用した @gunjo/ui コンポーネント
この画面のソースが直接 import している部品です。
cold AI が組み上げた実コード
ファイル名をクリックでソースを展開できます。
