DatePicker
DatePicker 从 HeroUI v2 到 v3 的迁移指南。
完整的 API 参考、样式指南与高级示例请参阅 v3 DatePicker 文档。本指南只关注从 HeroUI v2 的迁移。
结构变化
在 v2 中,DatePicker 是一个自包含组件,通过 props 处理标签、描述、日历和时间输入:
import { DatePicker } from "@lenso/ui";
export default function App() { return ( <DatePicker label="Birth date" /> );}在 v3 中,DatePicker 改用组合优先的 API,你需要显式组合 DateField 与 Calendar:
import { DatePicker, DateField, Calendar, Label } from "@lenso/ui";
export default function App() { return ( <DatePicker> <Label>Birth date</Label> <DateField.Group> <DateField.Input> {(segment) => <DateField.Segment segment={segment} />} </DateField.Input> <DateField.Suffix> <DatePicker.Trigger> <DatePicker.TriggerIndicator /> </DatePicker.Trigger> </DateField.Suffix> </DateField.Group> <DatePicker.Popover> <Calendar aria-label="Choose date"> <Calendar.Header> <Calendar.YearPickerTrigger> <Calendar.YearPickerTriggerHeading /> <Calendar.YearPickerTriggerIndicator /> </Calendar.YearPickerTrigger> <Calendar.NavButton slot="previous" /> <Calendar.NavButton slot="next" /> </Calendar.Header> <Calendar.Grid> <Calendar.GridHeader> {(day) => <Calendar.HeaderCell>{day}</Calendar.HeaderCell>} </Calendar.GridHeader> <Calendar.GridBody> {(date) => <Calendar.Cell date={date} />} </Calendar.GridBody> </Calendar.Grid> </Calendar> </DatePicker.Popover> </DatePicker> );}主要变化
1. 组件结构
v2: 单一 DatePicker 组件,所有部分(输入、日历、标签、popover)都通过 props 在内部处理
v3: 基于组合的 API,由 DatePicker、DateField、Calendar 和 Label 共同组成。每个部分都是独立组件。
2. 组成部分
| v3 组件 | 描述 |
|---|---|
DatePicker | 根容器与状态持有者 |
DatePicker.Trigger | 打开日历 popover 的按钮 |
DatePicker.TriggerIndicator | 日历图标(默认)或自定义指示器 |
DatePicker.Popover | 日历的 popover 包装层 |
DateField.Group | 输入组包装层 |
DateField.Input | 分段日期输入 |
DateField.Segment | 单独的日期片段(月、日、年) |
DateField.Suffix | 触发按钮的后缀 slot |
Calendar | 完整的日历组件(参见 Calendar 迁移) |
Label | 外部 Label 组件 |
3. Prop 变更
| v2 prop | v3 等效项 | 说明 |
|---|---|---|
value | value | 保持一致 |
defaultValue | defaultValue | 保持一致 |
onChange | onChange | 保持一致 |
minValue | minValue | 保持一致 |
maxValue | maxValue | 保持一致 |
isDateUnavailable | isDateUnavailable | 保持一致 |
isDisabled | isDisabled | 保持一致 |
isReadOnly | isReadOnly | 保持一致 |
isRequired | isRequired | 保持一致 |
isInvalid | isInvalid | 保持一致 |
granularity | granularity | 保持一致 |
hourCycle | hourCycle | 保持一致 |
hideTimeZone | hideTimeZone | 保持一致 |
shouldForceLeadingZeros | shouldForceLeadingZeros | 保持一致 |
pageBehavior | - | 直接设置在 Calendar 上 |
label | - | 使用 Label 组件 |
description | - | 使用 Description 组件 |
errorMessage | - | 使用 FieldError 组件 |
variant | - | 使用 DateField.Group 的 variant prop 或 Tailwind CSS |
color | - | 已移除(请改用 Tailwind CSS) |
size | - | 已移除(请改用 Tailwind CSS) |
radius | - | 已移除(请改用 Tailwind CSS) |
labelPlacement | - | 使用 Tailwind CSS 控制布局 |
startContent | - | 在 DateField.Group 内组合 |
endContent | - | 在 DateField.Group 内组合 |
selectorIcon | - | 将 children 传给 DatePicker.TriggerIndicator |
visibleMonths | - | 使用 Calendar 的 visibleDuration prop |
showMonthAndYearPickers | - | 使用 Calendar.YearPickerTrigger 和 Calendar.YearPickerGrid |
calendarProps | - | 直接将 props 传给 Calendar |
popoverProps | - | 直接将 props 传给 DatePicker.Popover |
selectorButtonProps | - | 直接将 props 传给 DatePicker.Trigger |
timeInputProps | - | 单独组合时间输入 |
CalendarBottomContent | - | 将内容放在 DatePicker.Popover 内、Calendar 之后 |
validate | - | 在外部处理校验 |
placeholderValue | placeholderValue | 保持一致 |
autoFocus | autoFocus | 保持一致 |
disableAnimation | - | 已移除 |
classNames | - | 在各个组件上使用 className |
迁移示例
基本日期选择器
import { DatePicker } from "@lenso/ui";
<DatePicker label="Birth date" />受控状态
import { useState } from "react";import { DatePicker } from "@lenso/ui";import { parseDate } from "@internationalized/date";
const [value, setValue] = useState(parseDate("2024-03-07"));
<DatePicker label="Date" value={value} onChange={setValue}/>带描述和错误信息
<DatePicker label="Event date" description="Choose a future date" errorMessage="Date must be in the future" isInvalid={isInvalid}/>自定义选择器图标
import { Icon } from "@iconify/react";
<DatePicker label="Date" selectorIcon={<Icon icon="gravity-ui:calendar" />}/>带月份 / 年份选择器和日历底部内容
<DatePicker label="Date" showMonthAndYearPickers CalendarBottomContent={ <button onClick={() => setValue(today(getLocalTimeZone()))}>Today</button> }/>样式变化
v2:classNames prop
<DatePicker classNames={{ base: "custom-base", selectorButton: "custom-trigger", selectorIcon: "custom-icon", popoverContent: "custom-popover", calendar: "custom-calendar", }}/>v3:直接使用 className prop
<DatePicker className="custom-base"> <Label>Date</Label> <DateField.Group> <DateField.Input> {(segment) => <DateField.Segment segment={segment} />} </DateField.Input> <DateField.Suffix> <DatePicker.Trigger className="custom-trigger"> <DatePicker.TriggerIndicator className="custom-icon" /> </DatePicker.Trigger> </DateField.Suffix> </DateField.Group> <DatePicker.Popover className="custom-popover"> <Calendar aria-label="Choose date" className="custom-calendar"> {/* Calendar compound components */} </Calendar> </DatePicker.Popover></DatePicker>组件结构
v3 DatePicker 遵循以下结构:
DatePicker (Root) ├── Label ├── DateField.Group │ ├── DateField.Input │ │ └── DateField.Segment (render prop per segment) │ └── DateField.Suffix │ └── DatePicker.Trigger │ └── DatePicker.TriggerIndicator ├── Description (optional) ├── FieldError (optional) └── DatePicker.Popover ├── Calendar (see Calendar migration guide) └── [Custom bottom content]总结
- 组件结构:单一组件 → 由
DatePicker、DateField、Calendar和Label组合而成 - 标签:
labelprop →Label组件 - 描述 / 错误信息:props →
Description和FieldError组件 - 日历:内置日历 → 在
DatePicker.Popover内组合带有自身复合组件的Calendar - 选择器图标:
selectorIconprop → 将 children 传给DatePicker.TriggerIndicator - 年份选择器:
showMonthAndYearPickersprop → 使用Calendar.YearPickerTrigger和Calendar.YearPickerGrid - 日历底部内容:
CalendarBottomContentprop → 将内容放在DatePicker.Popover内、Calendar之后 - 已移除样式 prop:
variant、color、size、radius→ 使用 Tailwind CSS 或DateField.Group的变体 - 已移除 classNames:在各个复合组件上使用
className - 多个月份:
visibleMonthsprop → 使用Calendar的visibleDurationprop