DateRangePicker
DateRangePicker 从 HeroUI v2 到 v3 的迁移指南。
完整的 API 参考、样式指南与高级示例请参阅 v3 DateRangePicker 文档。本指南只关注从 HeroUI v2 的迁移。
结构变化
在 v2 中,DateRangePicker 是单一自包含组件,通过 prop 配置标签、输入、日历与时间字段等:
import { DateRangePicker } from "@lenso/ui";
export default function App() { return ( <DateRangePicker label="Trip dates" /> );}在 v3 中,DateRangePicker 采用“组合优先”的 API,需要你显式组合 DateField 与 RangeCalendar:
import { DateField, DateRangePicker, Label, RangeCalendar } from "@lenso/ui";
export default function App() { return ( <DateRangePicker> <Label>Trip dates</Label> <DateField.Group> <DateField.InputContainer> <DateField.Input slot="start"> {(segment) => <DateField.Segment segment={segment} />} </DateField.Input> <DateRangePicker.RangeSeparator /> <DateField.Input slot="end"> {(segment) => <DateField.Segment segment={segment} />} </DateField.Input> </DateField.InputContainer> <DateField.Suffix> <DateRangePicker.Trigger> <DateRangePicker.TriggerIndicator /> </DateRangePicker.Trigger> </DateField.Suffix> </DateField.Group> <DateRangePicker.Popover> <RangeCalendar aria-label="Choose trip dates"> <RangeCalendar.Header> <RangeCalendar.YearPickerTrigger> <RangeCalendar.YearPickerTriggerHeading /> <RangeCalendar.YearPickerTriggerIndicator /> </RangeCalendar.YearPickerTrigger> <RangeCalendar.NavButton slot="previous" /> <RangeCalendar.NavButton slot="next" /> </RangeCalendar.Header> <RangeCalendar.Grid> <RangeCalendar.GridHeader> {(day) => <RangeCalendar.HeaderCell>{day}</RangeCalendar.HeaderCell>} </RangeCalendar.GridHeader> <RangeCalendar.GridBody> {(date) => <RangeCalendar.Cell date={date} />} </RangeCalendar.GridBody> </RangeCalendar.Grid> </RangeCalendar> </DateRangePicker.Popover> </DateRangePicker> );}主要变化
1. 组件结构
v2: 单一 DateRangePicker,两个输入、分隔符、日历、标签、popover 等主要由内部 prop 处理。
v3: 组合式 API:将 DateRangePicker、DateField、RangeCalendar 与 Label 等组合在一起;两个 DateField.Input 分别使用 slot="start" 与 slot="end" 表示范围输入。
2. 组合结构说明
| v3 组件 | 说明 |
|---|---|
DateRangePicker | 根容器与状态持有者 |
DateRangePicker.Trigger | 打开日历 popover 的按钮 |
DateRangePicker.TriggerIndicator | 日历图标(默认)或自定义指示器 |
DateRangePicker.RangeSeparator | 开始/结束日期输入之间的分隔符(默认 " - ") |
DateRangePicker.Popover | 包裹范围日历的 popover |
DateField.Group | 输入组外层 |
DateField.InputContainer | 开始/结束输入与分隔符容器 |
DateField.Input slot="start" | 开始日期的分段输入 |
DateField.Input slot="end" | 结束日期的分段输入 |
DateField.Segment | 单个日期片段(月/日/年等) |
DateField.Suffix | 触发按钮的后缀插槽 |
RangeCalendar | 完整范围日历(参见 RangeCalendar 迁移) |
Label | 外部标签组件 |
3. Prop 变更
| v2 prop | v3 对应 | 说明 |
|---|---|---|
value | value | 相同 |
defaultValue | defaultValue | 相同 |
onChange | onChange | 相同 |
minValue | minValue | 相同 |
maxValue | maxValue | 相同 |
isDisabled | isDisabled | 相同 |
isReadOnly | isReadOnly | 相同 |
isRequired | isRequired | 相同 |
isInvalid | isInvalid | 相同 |
isOpen | isOpen | 相同 |
defaultOpen | defaultOpen | 相同 |
onOpenChange | onOpenChange | 相同 |
granularity | granularity | 相同 |
hourCycle | hourCycle | 相同 |
hideTimeZone | hideTimeZone | 相同 |
shouldForceLeadingZeros | shouldForceLeadingZeros | 相同 |
allowsNonContiguousRanges | — | 直接在 RangeCalendar 上设置 |
pageBehavior | — | 直接在 RangeCalendar 上设置 |
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 控制布局 |
selectorIcon | — | 将 children 传给 DateRangePicker.TriggerIndicator |
selectorButtonPlacement | — | 通过 DateField.Prefix 或 DateField.Suffix 组合触发器位置 |
visibleMonths | — | 使用 RangeCalendar 的 visibleDuration prop |
showMonthAndYearPickers | — | 使用 RangeCalendar.YearPickerTrigger 与 RangeCalendar.YearPickerGrid |
calendarProps | — | 直接将 prop 传给 RangeCalendar |
popoverProps | — | 直接将 prop 传给 DateRangePicker.Popover |
selectorButtonProps | — | 直接将 prop 传给 DateRangePicker.Trigger |
timeInputProps | — | 时间输入需单独组合实现 |
calendarWidth | — | 已移除(请用 Tailwind CSS) |
validate | — | 在外部处理校验 |
placeholderValue | placeholderValue | 相同 |
autoFocus | autoFocus | 相同 |
disableAnimation | — | 已移除 |
classNames | — | 在各子组件上使用 className |
迁移示例
基础 DateRangePicker
import { DateRangePicker } from "@lenso/ui";
<DateRangePicker label="Trip dates" />受控状态
import { useState } from "react";import { DateRangePicker } from "@lenso/ui";import { parseDate } from "@internationalized/date";
const [value, setValue] = useState({ start: parseDate("2024-03-01"), end: parseDate("2024-03-14"),});
<DateRangePicker label="Trip dates" value={value} onChange={setValue}/>描述与错误信息
<DateRangePicker label="Trip dates" description="Select your travel period" errorMessage="End date must be after start date" isInvalid={isInvalid}/>自定义选择器图标
import { Icon } from "@iconify/react";
<DateRangePicker label="Trip dates" selectorIcon={<Icon icon="gravity-ui:calendar" />}/>多月份显示与年份选择器
<DateRangePicker label="Trip dates" visibleMonths={2} showMonthAndYearPickers/>样式相关变化
v2:classNames prop
<DateRangePicker classNames={{ base: "custom-base", label: "custom-label", selectorButton: "custom-trigger", selectorIcon: "custom-icon", separator: "custom-separator", popoverContent: "custom-popover", calendar: "custom-calendar", }}/>v3:直接使用 className
<DateRangePicker className="custom-base"> <Label className="custom-label">Trip dates</Label> <DateField.Group> <DateField.InputContainer> <DateField.Input slot="start"> {(segment) => <DateField.Segment segment={segment} />} </DateField.Input> <DateRangePicker.RangeSeparator className="custom-separator" /> <DateField.Input slot="end"> {(segment) => <DateField.Segment segment={segment} />} </DateField.Input> </DateField.InputContainer> <DateField.Suffix> <DateRangePicker.Trigger className="custom-trigger"> <DateRangePicker.TriggerIndicator className="custom-icon" /> </DateRangePicker.Trigger> </DateField.Suffix> </DateField.Group> <DateRangePicker.Popover className="custom-popover"> <RangeCalendar aria-label="Choose trip dates" className="custom-calendar"> {/* RangeCalendar compound components */} </RangeCalendar> </DateRangePicker.Popover></DateRangePicker>组件结构(Anatomy)
v3 的 DateRangePicker 结构如下:
DateRangePicker (Root) ├── Label ├── DateField.Group │ ├── DateField.InputContainer │ │ ├── DateField.Input slot="start" │ │ │ └── DateField.Segment(每个 segment 的渲染 prop) │ │ ├── DateRangePicker.RangeSeparator │ │ └── DateField.Input slot="end" │ │ └── DateField.Segment(每个 segment 的渲染 prop) │ └── DateField.Suffix │ └── DateRangePicker.Trigger │ └── DateRangePicker.TriggerIndicator ├── Description (optional) ├── FieldError (optional) └── DateRangePicker.Popover └── RangeCalendar (参见 RangeCalendar 迁移指南)总结
- 组件结构:由单一组件 → 组合
DateRangePicker、DateField、RangeCalendar与Label等。 - 双输入:内置起止输入 → 两个
DateField.Input,分别使用slot="start"与slot="end"。 - 分隔符:内置分隔 →
DateRangePicker.RangeSeparator。 - 标签:
labelprop →Label组件。 - 描述/错误:prop →
Description与FieldError组件。 - 日历:内置日历 → 在
DateRangePicker.Popover内组合RangeCalendar及其子组件。 - 选择器图标:
selectorIconprop → 将 children 传给DateRangePicker.TriggerIndicator。 - 年份选择器:
showMonthAndYearPickersprop → 使用RangeCalendar.YearPickerTrigger与RangeCalendar.YearPickerGrid。 - 样式类 prop 移除:
variant、color、size、radius→ 使用 Tailwind CSS,或DateField.Group的variant。 classNames移除:在各复合子组件上使用className。