"use client"; /** * InlineDateField — Pane 4 編集 UI の「日付 input」プリミティブ。 * * shadcn 公式 Date Picker パターンに完全準拠: * - `` + `` の組み合わせ * - 📅 アイコンを **左** に配置(shadcn 公式サンプルと同じ) * - トリガーの chrome は `` フィールドに揃える(border-input + bg-card) * ※ Button variant ではなく Input 風にする理由: * Pane 4 内の他フィールドと「箱」の濃淡を揃え、視覚的に浮かないようにする * - 値が空のときは「日付を選択」(shadcn "Pick a date" の翻訳) * - 日付の保存形式は ANSI / ISO 8601(YYYY-MM-DD) * - 月・年はドロップダウン(captionLayout="dropdown")。1925〜2050 の範囲で * 生年月日(過去)から入社可能日(未来)まで網羅する * * ADR-0014 で chromeless inline edit から shadcn 標準フォームへ転換した結果として * `components/primitives/` に切り出された再利用可能なプリミティブ。 */ import { useState } from "react"; import { Calendar as CalendarIcon } from "lucide-react"; import { Calendar } from "@/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { formatISODate, parseISODate } from "@/lib/computed/profile"; export type InlineDateFieldProps = { /** ISO 8601 (YYYY-MM-DD) 形式の文字列。空で「日付を選択」placeholder */ value: string; /** 値が変わったとき呼ばれる(ISO 8601 文字列を渡す) */ onSave: (v: string) => void; /** スクリーンリーダー向けラベル */ ariaLabel: string; }; export function InlineDateField({ value, onSave, ariaLabel, }: InlineDateFieldProps) { const [open, setOpen] = useState(false); const selected = parseISODate(value); return ( {value || "日付を選択"} { const next = formatISODate(d); if (next !== value) onSave(next); setOpen(false); }} captionLayout="dropdown" startMonth={new Date(1925, 0)} endMonth={new Date(2050, 11)} defaultMonth={selected ?? new Date()} autoFocus /> ); }