Date Picker 单日选择
用于单日选择场景的 MoriUI 组件。
导入
import { DatePicker } from 'moriui'
示例
概览
从弹层中选择日期。
<script setup lang="ts">
import { ref } from 'vue'
import { format } from 'date-fns'
import { zhCN } from 'date-fns/locale'
import { ChevronDown } from '@lucide/vue'
import {
DatePicker,
DatePickerCalendar,
DatePickerCell,
DatePickerCellTrigger,
DatePickerContent,
DatePickerGrid,
DatePickerGridBody,
DatePickerGridHead,
DatePickerGridRow,
DatePickerHeadCell,
DatePickerHeader,
DatePickerHeading,
DatePickerNext,
DatePickerPrev,
DatePickerTrigger
} from 'moriui'
const date = ref<Date>()
</script>
<template>
<DatePicker v-model="date" class="mx-auto w-fit">
<DatePickerTrigger class="flex w-[212px] items-center justify-between gap-2 rounded-lg border border-input bg-background px-3 py-2 text-left text-sm font-normal shadow-sm hover:bg-accent hover:text-accent-foreground data-[state=open]:ring-1 data-[state=open]:ring-ring">
<span :class="date ? 'text-foreground' : 'text-muted-foreground'">
{{ date ? format(date, 'PPP', { locale: zhCN }) : '选择日期' }}
</span>
<ChevronDown class="size-4 shrink-0 text-muted-foreground" />
</DatePickerTrigger>
<DatePickerContent class="w-auto rounded-lg border bg-popover p-0 shadow-md" align="start">
<DatePickerCalendar v-slot="{ grid, weekDays }">
<DatePickerHeader class="flex items-center justify-between px-3 pt-3">
<DatePickerPrev />
<DatePickerHeading class="text-sm font-medium" />
<DatePickerNext />
</DatePickerHeader>
<div class="p-3">
<DatePickerGrid v-for="month in grid" :key="month.value.toString()">
<DatePickerGridHead>
<DatePickerGridRow>
<DatePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DatePickerHeadCell>
</DatePickerGridRow>
</DatePickerGridHead>
<DatePickerGridBody>
<DatePickerGridRow v-for="(weekDates, index) in month.rows" :key="index">
<DatePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DatePickerCellTrigger :day="weekDate" :month="month.value" class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50" />
</DatePickerCell>
</DatePickerGridRow>
</DatePickerGridBody>
</DatePickerGrid>
</div>
</DatePickerCalendar>
</DatePickerContent>
</DatePicker>
</template>
基础
最小化的日期选择。
<script setup lang="ts">
import { ref } from 'vue'
import { format } from 'date-fns'
import { zhCN } from 'date-fns/locale'
import {
DatePicker,
DatePickerCalendar,
DatePickerCell,
DatePickerCellTrigger,
DatePickerContent,
DatePickerGrid,
DatePickerGridBody,
DatePickerGridHead,
DatePickerGridRow,
DatePickerHeadCell,
DatePickerHeader,
DatePickerHeading,
DatePickerNext,
DatePickerPrev,
DatePickerTrigger,
Label
} from 'moriui'
const date = ref<Date>()
</script>
<template>
<div class="mx-auto w-44">
<Label for="date-picker-simple" class="mb-2 block text-sm font-medium">日期</Label>
<DatePicker v-model="date">
<DatePickerTrigger
id="date-picker-simple"
class="flex w-full items-center justify-start gap-2 rounded-lg border border-input bg-background px-3 py-2 text-left text-sm font-normal shadow-sm hover:bg-accent hover:text-accent-foreground"
>
<span :class="date ? 'text-foreground' : 'text-muted-foreground'">
{{ date ? format(date, 'PPP', { locale: zhCN }) : '选择日期' }}
</span>
</DatePickerTrigger>
<DatePickerContent class="w-auto rounded-lg border bg-popover p-0 shadow-md" align="start">
<DatePickerCalendar v-slot="{ grid, weekDays }">
<DatePickerHeader class="flex items-center justify-between px-3 pt-3">
<DatePickerPrev />
<DatePickerHeading class="text-sm font-medium" />
<DatePickerNext />
</DatePickerHeader>
<div class="p-3">
<DatePickerGrid v-for="month in grid" :key="month.value.toString()">
<DatePickerGridHead>
<DatePickerGridRow>
<DatePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DatePickerHeadCell>
</DatePickerGridRow>
</DatePickerGridHead>
<DatePickerGridBody>
<DatePickerGridRow v-for="(weekDates, index) in month.rows" :key="index">
<DatePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DatePickerCellTrigger :day="weekDate" :month="month.value" class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50" />
</DatePickerCell>
</DatePickerGridRow>
</DatePickerGridBody>
</DatePickerGrid>
</div>
</DatePickerCalendar>
</DatePickerContent>
</DatePicker>
</div>
</template>
范围
选择日期区间。
<script setup lang="ts">
import type { DateValue } from 'reka-ui'
import { ref } from 'vue'
import { format } from 'date-fns'
import { Calendar } from '@lucide/vue'
import { zhCN } from 'date-fns/locale'
import { CalendarDate } from '@internationalized/date'
import {
DateRangePicker,
DateRangePickerCalendar,
DateRangePickerCell,
DateRangePickerCellTrigger,
DateRangePickerContent,
DateRangePickerGrid,
DateRangePickerGridBody,
DateRangePickerGridHead,
DateRangePickerGridRow,
DateRangePickerHeadCell,
DateRangePickerHeader,
DateRangePickerHeading,
DateRangePickerNext,
DateRangePickerPrev,
DateRangePickerTrigger,
Label
} from 'moriui'
function toNativeDate(d: DateValue | undefined): Date | undefined {
if (!d)
return undefined
if (d instanceof Date)
return d
if (d instanceof CalendarDate)
return d.toDate('UTC')
return undefined
}
const startDate = new Date(new Date().getFullYear(), 0, 20)
const date = ref<{ start?: DateValue, end?: DateValue }>({
start: new CalendarDate(startDate.getFullYear(), startDate.getMonth() + 1, startDate.getDate()),
end: new CalendarDate(
startDate.getFullYear(),
startDate.getMonth() + 1,
startDate.getDate() + 20
)
})
</script>
<template>
<div class="mx-auto w-60">
<Label for="date-picker-range" class="mb-2 block text-sm font-medium">日期范围</Label>
<DateRangePicker v-model="date" class="mx-auto w-fit">
<DateRangePickerTrigger
id="date-picker-range"
class="flex w-full items-center justify-start gap-2 rounded-lg border border-input bg-background px-2.5 py-2 text-left text-sm font-normal shadow-sm hover:bg-accent hover:text-accent-foreground"
>
<Calendar class="size-4 shrink-0 text-muted-foreground" />
<span v-if="date?.start" class="text-foreground">
<template v-if="date?.end">
{{ format(toNativeDate(date.start)!, 'MMM dd, y', { locale: zhCN }) }} - {{ format(toNativeDate(date.end)!, 'MMM dd, y', { locale: zhCN }) }}
</template>
<template v-else>
{{ format(toNativeDate(date.start)!, 'MMM dd, y', { locale: zhCN }) }}
</template>
</span>
<span v-else class="text-muted-foreground">选择日期范围</span>
</DateRangePickerTrigger>
<DateRangePickerContent class="w-auto rounded-lg border bg-popover p-0 shadow-md" align="start">
<DateRangePickerCalendar v-slot="{ grid, weekDays }">
<DateRangePickerHeader class="flex items-center justify-between px-3 pt-3">
<DateRangePickerPrev />
<DateRangePickerHeading class="text-sm font-medium" />
<DateRangePickerNext />
</DateRangePickerHeader>
<div class="p-3">
<DateRangePickerGrid v-for="month in grid" :key="month.value.toString()" class="[&:not(:first-child)]:ml-4">
<DateRangePickerGridHead>
<DateRangePickerGridRow>
<DateRangePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DateRangePickerHeadCell>
</DateRangePickerGridRow>
</DateRangePickerGridHead>
<DateRangePickerGridBody>
<DateRangePickerGridRow v-for="(weekDates, index) in month.rows" :key="index">
<DateRangePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DateRangePickerCellTrigger :day="weekDate" :month="month.value" class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50" />
</DateRangePickerCell>
</DateRangePickerGridRow>
</DateRangePickerGridBody>
</DateRangePickerGrid>
</div>
</DateRangePickerCalendar>
</DateRangePickerContent>
</DateRangePicker>
</div>
</template>
输入
手动输入日期。
<script setup lang="ts">
import { ref } from 'vue'
import { Calendar } from '@lucide/vue'
import { CalendarDate } from '@internationalized/date'
import {
DatePicker,
DatePickerCalendar,
DatePickerCell,
DatePickerCellTrigger,
DatePickerContent,
DatePickerGrid,
DatePickerGridBody,
DatePickerGridHead,
DatePickerGridRow,
DatePickerHeadCell,
DatePickerHeader,
DatePickerHeading,
DatePickerNext,
DatePickerPrev,
DatePickerTrigger,
Label
} from 'moriui'
function toNativeDate(date: unknown): Date | undefined {
if (!date)
return undefined
if (date instanceof Date)
return date
if (date instanceof CalendarDate)
return date.toDate('UTC')
return undefined
}
function formatDate(date: unknown): string {
const native = toNativeDate(date)
if (!native)
return ''
return native.toLocaleDateString('zh-CN', {
day: '2-digit',
month: 'long',
year: 'numeric'
})
}
function isValidDate(date: unknown): boolean {
const native = toNativeDate(date)
if (!native)
return false
return !isNaN(native.getTime())
}
const open = ref(false)
const date = ref<CalendarDate>(new CalendarDate(2025, 6, 1))
const placeholder = ref<Date | undefined>(new Date('2025-06-01'))
const value = ref(formatDate(date.value))
</script>
<template>
<div class="mx-auto w-48">
<Label for="date-required" class="mb-2 block text-sm font-medium">订阅日期</Label>
<div class="flex items-center rounded-lg border border-input bg-background shadow-sm focus-within:ring-1 focus-within:ring-ring">
<input
id="date-required"
:value="value"
placeholder="2025年6月1日"
class="flex-1 rounded-md bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
@input="(e: Event) => {
const target = e.target as HTMLInputElement
const parsed = new Date(target.value)
value = target.value
if (isValidDate(parsed)) {
date = new CalendarDate(parsed.getFullYear(), parsed.getMonth() + 1, parsed.getDate())
placeholder = parsed
}
}"
@keydown.arrow-down.prevent="open = true"
>
<DatePicker
v-model="date"
v-model:open="open"
:placeholder="placeholder"
@update:placeholder="placeholder = $event"
>
<DatePickerTrigger
class="mr-1 inline-flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground"
aria-label="选择日期"
>
<Calendar class="size-4" />
</DatePickerTrigger>
<DatePickerContent
class="w-auto rounded-lg border bg-popover p-0 shadow-md"
align="end"
:align-offset="-8"
:side-offset="10"
>
<DatePickerCalendar v-slot="{ grid, weekDays }">
<DatePickerHeader class="flex items-center justify-between px-3 pt-3">
<DatePickerPrev />
<DatePickerHeading class="text-sm font-medium" />
<DatePickerNext />
</DatePickerHeader>
<div class="p-3">
<DatePickerGrid v-for="monthItem in grid" :key="monthItem.value.toString()">
<DatePickerGridHead>
<DatePickerGridRow>
<DatePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DatePickerHeadCell>
</DatePickerGridRow>
</DatePickerGridHead>
<DatePickerGridBody>
<DatePickerGridRow v-for="(weekDates, index) in monthItem.rows" :key="index">
<DatePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DatePickerCellTrigger
:day="weekDate"
:month="monthItem.value"
class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50"
/>
</DatePickerCell>
</DatePickerGridRow>
</DatePickerGridBody>
</DatePickerGrid>
</div>
</DatePickerCalendar>
</DatePickerContent>
</DatePicker>
</div>
</div>
</template>
生日
选择出生日期。
<script setup lang="ts">
import { ref } from 'vue'
import {
DatePicker,
DatePickerCalendar,
DatePickerCell,
DatePickerCellTrigger,
DatePickerContent,
DatePickerGrid,
DatePickerGridBody,
DatePickerGridHead,
DatePickerGridRow,
DatePickerHeadCell,
DatePickerHeader,
DatePickerHeading,
DatePickerNext,
DatePickerPrev,
DatePickerTrigger,
Label
} from 'moriui'
const open = ref(false)
const date = ref<Date>()
</script>
<template>
<div class="mx-auto w-44">
<Label for="date" class="mb-2 block text-sm font-medium">出生日期</Label>
<DatePicker v-model="date" v-model:open="open" close-on-select>
<DatePickerTrigger
id="date"
class="flex w-full items-center justify-start gap-2 rounded-lg border border-input bg-background px-3 py-2 text-left text-sm font-normal shadow-sm hover:bg-accent hover:text-accent-foreground"
>
<span :class="date ? 'text-foreground' : 'text-muted-foreground'">
{{ date ? date.toLocaleDateString('zh-CN') : '选择日期' }}
</span>
</DatePickerTrigger>
<DatePickerContent class="w-auto rounded-lg border bg-popover p-0 shadow-md" align="start">
<DatePickerCalendar v-slot="{ grid, weekDays }">
<DatePickerHeader class="flex items-center justify-between px-3 pt-3">
<DatePickerPrev />
<DatePickerHeading class="text-sm font-medium" />
<DatePickerNext />
</DatePickerHeader>
<div class="p-3">
<DatePickerGrid v-for="month in grid" :key="month.value.toString()">
<DatePickerGridHead>
<DatePickerGridRow>
<DatePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DatePickerHeadCell>
</DatePickerGridRow>
</DatePickerGridHead>
<DatePickerGridBody>
<DatePickerGridRow v-for="(weekDates, index) in month.rows" :key="index">
<DatePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DatePickerCellTrigger
:day="weekDate"
:month="month.value"
class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50"
/>
</DatePickerCell>
</DatePickerGridRow>
</DatePickerGridBody>
</DatePickerGrid>
</div>
</DatePickerCalendar>
</DatePickerContent>
</DatePicker>
</div>
</template>
时间
日期时间选择。
<script setup lang="ts">
import { ref } from 'vue'
import { format } from 'date-fns'
import { zhCN } from 'date-fns/locale'
import { ChevronDown } from '@lucide/vue'
import {
DatePicker,
DatePickerCalendar,
DatePickerCell,
DatePickerCellTrigger,
DatePickerContent,
DatePickerGrid,
DatePickerGridBody,
DatePickerGridHead,
DatePickerGridRow,
DatePickerHeadCell,
DatePickerHeader,
DatePickerHeading,
DatePickerNext,
DatePickerPrev,
DatePickerTrigger,
Field,
FieldGroup,
FieldLabel,
Input
} from 'moriui'
const open = ref(false)
const date = ref<Date>()
</script>
<template>
<FieldGroup class="mx-auto flex max-w-xs flex-row gap-4">
<Field>
<FieldLabel for="date-picker-optional" class="text-sm font-medium">
日期
</FieldLabel>
<DatePicker v-model="date" v-model:open="open">
<DatePickerTrigger
id="date-picker-optional"
class="flex w-32 items-center justify-between gap-2 rounded-lg border border-input bg-background px-3 py-2 text-left text-sm font-normal shadow-sm hover:bg-accent hover:text-accent-foreground"
>
<span :class="date ? 'text-foreground' : 'text-muted-foreground'">
{{ date ? format(date, 'PPP', { locale: zhCN }) : '选择日期' }}
</span>
<ChevronDown class="size-4 shrink-0 text-muted-foreground" />
</DatePickerTrigger>
<DatePickerContent class="w-auto rounded-lg border bg-popover p-0 shadow-md" align="start">
<DatePickerCalendar v-slot="{ grid, weekDays }">
<DatePickerHeader class="flex items-center justify-between px-3 pt-3">
<DatePickerPrev />
<DatePickerHeading class="text-sm font-medium" />
<DatePickerNext />
</DatePickerHeader>
<div class="p-3">
<DatePickerGrid v-for="month in grid" :key="month.value.toString()">
<DatePickerGridHead>
<DatePickerGridRow>
<DatePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DatePickerHeadCell>
</DatePickerGridRow>
</DatePickerGridHead>
<DatePickerGridBody>
<DatePickerGridRow v-for="(weekDates, index) in month.rows" :key="index">
<DatePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DatePickerCellTrigger
:day="weekDate"
:month="month.value"
class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50"
/>
</DatePickerCell>
</DatePickerGridRow>
</DatePickerGridBody>
</DatePickerGrid>
</div>
</DatePickerCalendar>
</DatePickerContent>
</DatePicker>
</Field>
<Field class="w-32">
<FieldLabel for="time-picker-optional" class="text-sm font-medium">
时间
</FieldLabel>
<Input
id="time-picker-optional"
type="time"
step="1"
default-value="10:30:00"
class="block w-full appearance-none rounded-lg border border-input bg-background px-3 py-2 text-sm shadow-sm [&::-webkit-calendar-picker-indicator]:hidden"
/>
</Field>
</FieldGroup>
</template>
自然语言
自然语言输入日期。
你的文章将于 发布。
<script setup lang="ts">
import { ref } from 'vue'
import { Calendar } from '@lucide/vue'
import { parseDate } from 'chrono-node'
import { CalendarDate } from '@internationalized/date'
import {
DatePicker,
DatePickerCalendar,
DatePickerCell,
DatePickerCellTrigger,
DatePickerContent,
DatePickerGrid,
DatePickerGridBody,
DatePickerGridHead,
DatePickerGridRow,
DatePickerHeadCell,
DatePickerHeader,
DatePickerHeading,
DatePickerNext,
DatePickerPrev,
DatePickerTrigger,
Label
} from 'moriui'
function toNativeDate(date: unknown): Date | undefined {
if (!date)
return undefined
if (date instanceof Date)
return date
if (date instanceof CalendarDate)
return date.toDate('UTC')
return undefined
}
function formatDate(date: unknown): string {
const native = toNativeDate(date)
if (!native)
return ''
return native.toLocaleDateString('zh-CN', {
day: '2-digit',
month: 'long',
year: 'numeric'
})
}
const open = ref(false)
const value = ref('后天')
const now = new Date()
const initialDate = parseDate(value.value)
const date = ref<CalendarDate | undefined>(
initialDate ? new CalendarDate(initialDate.getFullYear(), initialDate.getMonth() + 1, initialDate.getDate()) : undefined
)
</script>
<template>
<div class="mx-auto max-w-xs">
<Label for="date-optional" class="mb-2 block text-sm font-medium">日程日期</Label>
<div class="flex items-center rounded-lg border border-input bg-background shadow-sm focus-within:ring-1 focus-within:ring-ring">
<input
id="date-optional"
:value="value"
placeholder="明天或下周"
class="flex-1 rounded-md bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
@input="(e: Event) => {
const target = e.target as HTMLInputElement
value = target.value
const parsed = parseDate(target.value)
if (parsed) date = new CalendarDate(parsed.getFullYear(), parsed.getMonth() + 1, parsed.getDate())
}"
@keydown.arrow-down.prevent="open = true"
>
<DatePicker v-model="date" v-model:open="open">
<DatePickerTrigger
class="mr-1 inline-flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground"
aria-label="选择日期"
>
<Calendar class="size-4" />
</DatePickerTrigger>
<DatePickerContent class="w-auto rounded-lg border bg-popover p-0 shadow-md" align="end" :side-offset="8">
<DatePickerCalendar v-slot="{ grid, weekDays }">
<DatePickerHeader class="flex items-center justify-between px-3 pt-3">
<DatePickerPrev />
<DatePickerHeading class="text-sm font-medium" />
<DatePickerNext />
</DatePickerHeader>
<div class="p-3">
<DatePickerGrid v-for="month in grid" :key="month.value.toString()">
<DatePickerGridHead>
<DatePickerGridRow>
<DatePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DatePickerHeadCell>
</DatePickerGridRow>
</DatePickerGridHead>
<DatePickerGridBody>
<DatePickerGridRow v-for="(weekDates, index) in month.rows" :key="index">
<DatePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DatePickerCellTrigger
:day="weekDate"
:month="month.value"
class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50"
/>
</DatePickerCell>
</DatePickerGridRow>
</DatePickerGridBody>
</DatePickerGrid>
</div>
</DatePickerCalendar>
</DatePickerContent>
</DatePicker>
</div>
<p class="mt-2 px-1 text-sm text-muted-foreground">
你的文章将于 <span class="font-medium text-foreground">{{ formatDate(date) }}</span> 发布。
</p>
</div>
</template>
RTL
从右到左的日期选择。
<script setup lang="ts">
import { ref } from 'vue'
import { format } from 'date-fns'
import { arSA } from 'date-fns/locale'
import { ChevronDown } from '@lucide/vue'
import {
DatePicker,
DatePickerCalendar,
DatePickerCell,
DatePickerCellTrigger,
DatePickerContent,
DatePickerGrid,
DatePickerGridBody,
DatePickerGridHead,
DatePickerGridRow,
DatePickerHeadCell,
DatePickerHeader,
DatePickerHeading,
DatePickerNext,
DatePickerPrev,
DatePickerTrigger,
DirectionProvider
} from 'moriui'
const date = ref<Date>()
</script>
<template>
<DirectionProvider dir="rtl">
<DatePicker v-model="date" class="mx-auto w-fit">
<DatePickerTrigger class="flex w-[212px] items-center justify-between gap-2 rounded-lg border border-input bg-background px-3 py-2 text-left text-sm font-normal shadow-sm hover:bg-accent hover:text-accent-foreground data-[state=open]:ring-1 data-[state=open]:ring-ring">
<span :class="date ? 'text-foreground' : 'text-muted-foreground'">
{{ date ? format(date, 'PPP', { locale: arSA }) : 'اختر تاريخًا' }}
</span>
<ChevronDown class="size-4 shrink-0 text-muted-foreground" />
</DatePickerTrigger>
<DatePickerContent class="w-auto rounded-lg border bg-popover p-0 shadow-md" align="start">
<DatePickerCalendar v-slot="{ grid, weekDays }">
<DatePickerHeader class="flex items-center justify-between px-3 pt-3">
<DatePickerPrev />
<DatePickerHeading class="text-sm font-medium" />
<DatePickerNext />
</DatePickerHeader>
<div class="p-3">
<DatePickerGrid v-for="month in grid" :key="month.value.toString()">
<DatePickerGridHead>
<DatePickerGridRow>
<DatePickerHeadCell v-for="day in weekDays" :key="day" class="h-8 w-8 text-center text-xs text-muted-foreground">
{{ day }}
</DatePickerHeadCell>
</DatePickerGridRow>
</DatePickerGridHead>
<DatePickerGridBody>
<DatePickerGridRow v-for="(weekDates, index) in month.rows" :key="index">
<DatePickerCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="h-8 w-8 p-0"
>
<DatePickerCellTrigger :day="weekDate" :month="month.value" class="flex h-8 w-8 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground data-selected:bg-primary data-selected:text-primary-foreground data-today:bg-accent data-today:text-accent-foreground data-outside-view:text-muted-foreground/50" />
</DatePickerCell>
</DatePickerGridRow>
</DatePickerGridBody>
</DatePickerGrid>
</div>
</DatePickerCalendar>
</DatePickerContent>
</DatePicker>
</DirectionProvider>
</template>
使用说明
组合方式
DatePicker 组合 Calendar 和 Popover,通过 Trigger 打开日历弹层。
预设
与日历 preset 组合可提供快捷日期范围。
RTL
弹层定位与日历方向遵循 dir。
变体
DatePicker 没有视觉变体;弹层定位由 Popper 控制。
可访问性
DatePicker 将 Calendar 的 grid 语义放置在 Popover 弹层中,焦点在打开时移动到日历。输入框应有 Label 或 aria-label。
API 参考
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
DatePicker v-model | DateValue | null | undefined | 当前选中日期。 |
DatePicker placeholder | DateValue | undefined | 无选择时的占位日期。 |
DatePickerInput class | HTMLAttributes["class"] | undefined | 合并到输入框的调用方类。 |
DatePickerContent side / align | PopperContentProps | 'bottom' / 'center' | 弹层定位属性。 |