Skip to content
Lenso UI

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 propv3 对应说明
valuevalue相同
defaultValuedefaultValue相同
onChangeonChange相同
minValueminValue相同
maxValuemaxValue相同
isDisabledisDisabled相同
isReadOnlyisReadOnly相同
isRequiredisRequired相同
isInvalidisInvalid相同
isOpenisOpen相同
defaultOpendefaultOpen相同
onOpenChangeonOpenChange相同
granularitygranularity相同
hourCyclehourCycle相同
hideTimeZonehideTimeZone相同
shouldForceLeadingZerosshouldForceLeadingZeros相同
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—在外部处理校验
placeholderValueplaceholderValue相同
autoFocusautoFocus相同
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 迁移指南)

总结

  1. 组件结构:由单一组件 → 组合 DateRangePicker、DateField、RangeCalendar 与 Label 等。
  2. 双输入:内置起止输入 → 两个 DateField.Input,分别使用 slot="start" 与 slot="end"。
  3. 分隔符:内置分隔 → DateRangePicker.RangeSeparator。
  4. 标签:label prop → Label 组件。
  5. 描述/错误:prop → Description 与 FieldError 组件。
  6. 日历:内置日历 → 在 DateRangePicker.Popover 内组合 RangeCalendar 及其子组件。
  7. 选择器图标:selectorIcon prop → 将 children 传给 DateRangePicker.TriggerIndicator。
  8. 年份选择器:showMonthAndYearPickers prop → 使用 RangeCalendar.YearPickerTrigger 与 RangeCalendar.YearPickerGrid。
  9. 样式类 prop 移除:variant、color、size、radius → 使用 Tailwind CSS,或 DateField.Group 的 variant。
  10. classNames 移除:在各复合子组件上使用 className。