feat: update

This commit is contained in:
Sadegh Barati 2024-04-04 14:35:48 +03:30
parent f6a3879582
commit 6795b8fdfa
52 changed files with 1717 additions and 33 deletions

View File

@ -183,7 +183,7 @@ export const docsConfig: DocsConfig = {
title: 'Calendar',
href: '/docs/components/calendar',
items: [],
label: 'New',
label: 'Updated',
},
{
title: 'Card',
@ -226,6 +226,12 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/data-table',
items: [],
},
{
title: 'Date Picker',
href: '/docs/components/date-picker',
items: [],
label: 'Updated',
},
{
title: 'Dialog',
href: '/docs/components/dialog',
@ -298,6 +304,12 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/radio-group',
items: [],
},
{
title: 'Range Calendar',
href: '/docs/components/range-calendar',
items: [],
label: 'New',
},
{
title: 'Resizable',
href: '/docs/components/resizable',

View File

@ -202,7 +202,7 @@ export const Index = {
"CalendarWithSelect": {
name: "CalendarWithSelect",
type: "components:example",
registryDependencies: [],
registryDependencies: ["calendar","select","utils"],
component: () => import("../src/lib/registry/default/example/CalendarWithSelect.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/CalendarWithSelect.vue"],
},
@ -409,6 +409,34 @@ export const Index = {
component: () => import("../src/lib/registry/default/example/DataTableDemoColumn.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/DataTableDemoColumn.vue"],
},
"DatePickerDemo": {
name: "DatePickerDemo",
type: "components:example",
registryDependencies: ["calendar","button","popover","utils"],
component: () => import("../src/lib/registry/default/example/DatePickerDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/DatePickerDemo.vue"],
},
"DatePickerForm": {
name: "DatePickerForm",
type: "components:example",
registryDependencies: [],
component: () => import("../src/lib/registry/default/example/DatePickerForm.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/DatePickerForm.vue"],
},
"DatePickerWithPresets": {
name: "DatePickerWithPresets",
type: "components:example",
registryDependencies: [],
component: () => import("../src/lib/registry/default/example/DatePickerWithPresets.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/DatePickerWithPresets.vue"],
},
"DatePickerWithRange": {
name: "DatePickerWithRange",
type: "components:example",
registryDependencies: ["range-calendar","button","popover","utils"],
component: () => import("../src/lib/registry/default/example/DatePickerWithRange.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/DatePickerWithRange.vue"],
},
"DialogCustomCloseButton": {
name: "DialogCustomCloseButton",
type: "components:example",
@ -633,6 +661,13 @@ export const Index = {
component: () => import("../src/lib/registry/default/example/RadioGroupForm.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/RadioGroupForm.vue"],
},
"RangeCalendarDemo": {
name: "RangeCalendarDemo",
type: "components:example",
registryDependencies: ["range-calendar"],
component: () => import("../src/lib/registry/default/example/RangeCalendarDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/default/example/RangeCalendarDemo.vue"],
},
"ResizableDemo": {
name: "ResizableDemo",
type: "components:example",
@ -1379,7 +1414,7 @@ export const Index = {
"CalendarWithSelect": {
name: "CalendarWithSelect",
type: "components:example",
registryDependencies: [],
registryDependencies: ["calendar","select","utils"],
component: () => import("../src/lib/registry/new-york/example/CalendarWithSelect.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/CalendarWithSelect.vue"],
},
@ -1586,6 +1621,34 @@ export const Index = {
component: () => import("../src/lib/registry/new-york/example/DataTableDemoColumn.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/DataTableDemoColumn.vue"],
},
"DatePickerDemo": {
name: "DatePickerDemo",
type: "components:example",
registryDependencies: ["calendar","button","popover","utils"],
component: () => import("../src/lib/registry/new-york/example/DatePickerDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/DatePickerDemo.vue"],
},
"DatePickerForm": {
name: "DatePickerForm",
type: "components:example",
registryDependencies: [],
component: () => import("../src/lib/registry/new-york/example/DatePickerForm.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/DatePickerForm.vue"],
},
"DatePickerWithPresets": {
name: "DatePickerWithPresets",
type: "components:example",
registryDependencies: [],
component: () => import("../src/lib/registry/new-york/example/DatePickerWithPresets.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/DatePickerWithPresets.vue"],
},
"DatePickerWithRange": {
name: "DatePickerWithRange",
type: "components:example",
registryDependencies: ["range-calendar","button","popover","utils"],
component: () => import("../src/lib/registry/new-york/example/DatePickerWithRange.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/DatePickerWithRange.vue"],
},
"DialogCustomCloseButton": {
name: "DialogCustomCloseButton",
type: "components:example",
@ -1810,6 +1873,13 @@ export const Index = {
component: () => import("../src/lib/registry/new-york/example/RadioGroupForm.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/RadioGroupForm.vue"],
},
"RangeCalendarDemo": {
name: "RangeCalendarDemo",
type: "components:example",
registryDependencies: ["range-calendar"],
component: () => import("../src/lib/registry/new-york/example/RangeCalendarDemo.vue").then((m) => m.default),
files: ["../src/lib/registry/new-york/example/RangeCalendarDemo.vue"],
},
"ResizableDemo": {
name: "ResizableDemo",
type: "components:example",

View File

@ -7,15 +7,21 @@ primitive: https://www.radix-vue.com/components/calendar.html
<ComponentPreview name="CalendarDemo" />
<Callout class="text-base mt-12">
If you're looking for **previous** Calendar implementation, checkout to <span class="font-bold underline">[VCalendar](/docs/components/v-calendar)</span> component
</Callout>
## About
The `<Calendar />` component is built on top of the [RadixVue Calendar](https://www.radix-vue.com/components/calendar.html) component, which uses the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package to handle dates.
If you're looking for a range calendar, check out the [Range Calendar](#asdasd) component.
If you're looking for a range calendar, check out the [Range Calendar](/docs/components/range-calendar) component.
## Installation
```shell
```bash
npx shadcn-vue@latest add calendar
```

View File

@ -0,0 +1,38 @@
---
title: Date Picker
description: A date picker component with range and presets.
source: apps/www/src/lib/registry/default/example/DatePickerDemo.vue
primitive: https://www.radix-vue.com/components/calendar.html
---
<ComponentPreview name="DatePickerDemo" />
<Callout class="text-base mt-12">
If you're looking for **previous** Date Picker implementation, checkout to <span class="font-bold underline">[VCalendar Datepicker](/docs/components/v-date-picker)</span> component
</Callout>
## Installation
The Date Picker is built using a composition of the `<Popover />` and either the `<Calendar />` or `<RangeCalendar />` components.
See installations instructions for the [Popover](/docs/components/popover), [Calendar](/docs/components/calendar), and [Range Calendar](/docs/components/range-calendar) components.
## Examples
### Date Picker
<ComponentPreview name="DatePickerDemo" />
### Date Range Picker
<ComponentPreview name="DatePickerWithRange" />
### With Presets
<ComponentPreview name="DatePickerWithPresets" />
### Form
<ComponentPreview name="DatePickerForm" />

View File

@ -0,0 +1,18 @@
---
title: Range Calendar
description: A calendar component that allows users to select a range of dates.
source: apps/www/src/lib/registry/default/ui/range-calendar
primitive: https://www.radix-vue.com/components/range-calendar.html
---
<ComponentPreview name="RangeCalendarDemo" />
## About
The `<RangeCalendar />` component is built on top of the [RadixVue Range Calendar](https://www.bits-ui.com/docs/components/range-calendar) component, which uses the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package to handle dates.
## Installation
```bash
npx shadcn-vue@latest add range-calendar
```

View File

@ -1,5 +1,5 @@
---
title: Calendar
title: VCalendar
description: A date field component that allows users to enter and edit date.
source: apps/www/src/lib/registry/default/ui/calendar
primitive: https://vcalendar.io/
@ -17,7 +17,7 @@ The `Calendar` component is built on top of [VCalendar](https://vcalendar.io/get
<template #CLI>
```bash
npx shadcn-vue@latest add calendar
npx shadcn-vue@latest add v-calendar
```
</template>

View File

@ -1,5 +1,5 @@
---
title: Date Picker
title: VCalendar Date Picker
description: A date picker component with range and presets.
---

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import { type HTMLAttributes, type Ref, computed, onMounted, ref, toRaw, toRef } from 'vue'
import { type HTMLAttributes, type Ref, computed, toRef } from 'vue'
import { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, toDate, useForwardPropsEmits } from 'radix-vue'
import { type DateValue, GregorianCalendar, getLocalTimeZone, toCalendar, today } from '@internationalized/date'
import { type DateValue, getLocalTimeZone, today } from '@internationalized/date'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading } from '@/lib/registry/default/ui/calendar'
import {
Select,

View File

@ -0,0 +1,40 @@
<script setup lang="ts">
import { ref } from 'vue'
import {
DateFormatter,
type DateValue,
getLocalTimeZone,
} from '@internationalized/date'
import { Calendar as CalendarIcon } from 'lucide-vue-next'
import { Calendar } from '@/lib/registry/default/ui/calendar'
import { Button } from '@/lib/registry/default/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/default/ui/popover'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'long',
})
const value = ref<DateValue>()
</script>
<template>
<Popover>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!value && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
{{ value ? df.format(value.toDate(getLocalTimeZone())) : "Pick a date" }}
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<Calendar v-model="value" initial-focus />
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,109 @@
<script setup lang="ts">
import { computed, h, ref } from 'vue'
import { CalendarDate, DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date'
import { toDate } from 'radix-vue'
import { Calendar as CalendarIcon } from 'lucide-vue-next'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'
import { Calendar } from '@/lib/registry/default/ui/calendar'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/default/ui/popover'
import { toast } from '@/lib/registry/default/ui/toast'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'long',
})
const formSchema = toTypedSchema(z.object({
dob: z
.string()
.refine(v => v, { message: 'A date of birth is required.' }),
}))
const placeholder = ref()
const { handleSubmit, setValues, values } = useForm({
validationSchema: formSchema,
initialValues: {
},
})
const value = computed({
get: () => values.dob ? parseDate(values.dob) : undefined,
set: val => val,
})
const onSubmit = handleSubmit((values) => {
toast({
title: 'You submitted the following values:',
description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),
})
})
</script>
<template>
<form class="space-y-8" @submit="onSubmit">
<FormField name="dob">
<FormItem class="flex flex-col">
<FormLabel>Date of birth</FormLabel>
<Popover>
<PopoverTrigger as-child>
<FormControl>
<Button
variant="outline" :class="cn(
'w-[240px] ps-3 text-start font-normal',
!value && 'text-muted-foreground',
)"
>
<span>{{ value ? df.format(toDate(value)) : "Pick a date" }}</span>
<CalendarIcon class="ms-auto h-4 w-4 opacity-50" />
</Button>
<input hidden>
</FormControl>
</PopoverTrigger>
<PopoverContent class="p-0">
<Calendar
v-model:placeholder="placeholder"
v-model="value"
calendar-label="Date of birth"
initial-focus
:min-value="new CalendarDate(1900, 1, 1)"
:max-value="today(getLocalTimeZone())"
@update:model-value="(v) => {
if (v) {
setValues({
dob: v.toString(),
})
}
else {
setValues({
dob: '',
})
}
}"
/>
</PopoverContent>
</Popover>
<FormDescription>
Your date of birth is used to calculate your age.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</Form>
</template>

View File

@ -0,0 +1,64 @@
<script setup lang="ts">
import { ref } from 'vue'
import {
DateFormatter,
type DateValue,
getLocalTimeZone,
today,
} from '@internationalized/date'
import { Calendar as CalendarIcon } from 'lucide-vue-next'
import { Calendar } from '@/lib/registry/default/ui/calendar'
import { Button } from '@/lib/registry/default/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/default/ui/popover'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/lib/registry/default/ui/select'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'long',
})
const items = [
{ value: 0, label: 'Today' },
{ value: 1, label: 'Tomorrow' },
{ value: 3, label: 'In 3 days' },
{ value: 7, label: 'In a week' },
]
const value = ref<DateValue>()
</script>
<template>
<Popover onfocus>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!value && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
{{ value ? df.format(value.toDate(getLocalTimeZone())) : "Pick a date" }}
</Button>
</PopoverTrigger>
<PopoverContent class="flex w-auto flex-col gap-y-2 p-2">
<Select
@update:model-value="(v) => {
if (!v) return;
value = today(getLocalTimeZone()).add({ days: Number(v) });
}"
>
<SelectTrigger>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="item in items" :key="item.value" :value="item.value.toString()">
{{ item.label }}
</SelectItem>
</SelectContent>
</Select>
<Calendar v-model="value" />
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,52 @@
<script setup lang="ts">
import { type Ref, ref } from 'vue'
import {
CalendarDate,
DateFormatter,
getLocalTimeZone,
} from '@internationalized/date'
import { Calendar as CalendarIcon } from 'lucide-vue-next'
import type { DateRange } from 'radix-vue'
import { RangeCalendar } from '@/lib/registry/default/ui/range-calendar'
import { Button } from '@/lib/registry/default/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/default/ui/popover'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'medium',
})
const value = ref({
start: new CalendarDate(2022, 1, 20),
end: new CalendarDate(2022, 1, 20).add({ days: 20 }),
}) as Ref<DateRange>
</script>
<template>
<Popover>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!value && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="value.start">
<template v-if="value.end">
{{ df.format(value.start.toDate(getLocalTimeZone())) }} - {{ df.format(value.end.toDate(getLocalTimeZone())) }}
</template>
<template v-else>
{{ df.format(value.start.toDate(getLocalTimeZone())) }}
</template>
</template>
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<RangeCalendar v-model="value" initial-focus :number-of-months="2" :placeholder="value?.start" />
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,18 @@
<script setup lang="ts">
import { type Ref, ref } from 'vue'
import type { DateRange } from 'radix-vue'
import { getLocalTimeZone, today } from '@internationalized/date'
import { RangeCalendar } from '@/lib/registry/default/ui/range-calendar'
const start = today(getLocalTimeZone())
const end = start.add({ days: 7 })
const value = ref({
start,
end,
}) as Ref<DateRange>
</script>
<template>
<RangeCalendar v-model="value" class="rounded-md border" />
</template>

View File

@ -1,5 +1,4 @@
<script lang="ts" setup>
import type { HTMLAttributes } from 'vue'
import { CalendarGridHead, type CalendarGridHeadProps } from 'radix-vue'
const props = defineProps<CalendarGridHeadProps>()

View File

@ -0,0 +1,60 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarRoot, type RangeCalendarRootEmits, type RangeCalendarRootProps, useForwardPropsEmits } from 'radix-vue'
import { RangeCalendarCell, RangeCalendarCellTrigger, RangeCalendarGrid, RangeCalendarGridBody, RangeCalendarGridHead, RangeCalendarGridRow, RangeCalendarHeadCell, RangeCalendarHeader, RangeCalendarHeading, RangeCalendarNextButton, RangeCalendarPrevButton } from '.'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarRootProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<RangeCalendarRootEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<RangeCalendarRoot
v-slot="{ grid, weekDays }"
:class="cn('p-3', props.class)"
v-bind="forwarded"
>
<RangeCalendarHeader>
<RangeCalendarPrevButton />
<RangeCalendarHeading />
<RangeCalendarNextButton />
</RangeCalendarHeader>
<div class="flex flex-col space-y-4 pt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0">
<RangeCalendarGrid v-for="month in grid" :key="month.value.toString()">
<RangeCalendarGridHead>
<RangeCalendarGridRow class="mb-1 grid w-full grid-cols-7">
<RangeCalendarHeadCell
v-for="day in weekDays" :key="day"
>
{{ day }}
</RangeCalendarHeadCell>
</RangeCalendarGridRow>
</RangeCalendarGridHead>
<RangeCalendarGridBody class="grid">
<RangeCalendarGridRow v-for="(weekDates, index) in month.rows" :key="`weekDate-${index}`" class="grid grid-cols-7">
<RangeCalendarCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
>
<RangeCalendarCellTrigger
:day="weekDate"
:month="month.value"
/>
</RangeCalendarCell>
</RangeCalendarGridRow>
</RangeCalendarGridBody>
</RangeCalendarGrid>
</div>
</RangeCalendarRoot>
</template>

View File

@ -0,0 +1,24 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarCell, type RangeCalendarCellProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarCellProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarCell
:class="cn('relative h-9 w-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:bg-accent first:[&:has([data-selected])]:rounded-l-md last:[&:has([data-selected])]:rounded-r-md [&:has([data-selected][data-outside-month])]:bg-accent/50 [&:has([data-selected][data-selection-end])]:rounded-r-md [&:has([data-selected][data-selection-start])]:rounded-l-md', props.class)"
v-bind="forwardedProps"
>
<slot />
</RangeCalendarCell>
</template>

View File

@ -0,0 +1,40 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarCellTrigger, type RangeCalendarCellTriggerProps, useForwardProps } from 'radix-vue'
import { buttonVariants } from '@/lib/registry/default/ui/button'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarCellTriggerProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarCellTrigger
:class="cn(
buttonVariants({ variant: 'ghost' }),
'h-9 w-9 p-0 font-normal data-[selected]:opacity-100',
'[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground',
// Selection Start
'data-[selection-start]:bg-primary data-[selection-start]:text-primary-foreground data-[selection-start]:hover:bg-primary data-[selection-start]:hover:text-primary-foreground data-[selection-start]:focus:bg-primary data-[selection-start]:focus:text-primary-foreground',
// Selection End
'data-[selection-end]:bg-primary data-[selection-end]:text-primary-foreground data-[selection-end]:hover:bg-primary data-[selection-end]:hover:text-primary-foreground data-[selection-end]:focus:bg-primary data-[selection-end]:focus:text-primary-foreground',
// Outside months
'data-[outside-month]:pointer-events-none data-[outside-month]:text-muted-foreground data-[outside-month]:opacity-50 [&[data-outside-month][data-selected]]:bg-accent/50 [&[data-outside-month][data-selected]]:text-muted-foreground [&[data-outside-month][data-selected]]:opacity-30',
// Disabled
'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',
// Unavailable
'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through',
props.class,
)"
v-bind="forwardedProps"
>
<slot />
</RangeCalendarCellTrigger>
</template>

View File

@ -0,0 +1,24 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarGrid, type RangeCalendarGridProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarGridProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarGrid
:class="cn('w-full border-collapse space-y-1', props.class)"
v-bind="forwardedProps"
>
<slot />
</RangeCalendarGrid>
</template>

View File

@ -0,0 +1,11 @@
<script lang="ts" setup>
import { RangeCalendarGridBody, type RangeCalendarGridBodyProps } from 'radix-vue'
const props = defineProps<RangeCalendarGridBodyProps>()
</script>
<template>
<RangeCalendarGridBody v-bind="props">
<slot />
</RangeCalendarGridBody>
</template>

View File

@ -0,0 +1,11 @@
<script lang="ts" setup>
import { RangeCalendarGridHead, type RangeCalendarGridHeadProps } from 'radix-vue'
const props = defineProps<RangeCalendarGridHeadProps>()
</script>
<template>
<RangeCalendarGridHead v-bind="props">
<slot />
</RangeCalendarGridHead>
</template>

View File

@ -0,0 +1,21 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarGridRow, type RangeCalendarGridRowProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarGridRowProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarGridRow :class="cn('flex mt-2 w-full', props.class)" v-bind="forwardedProps">
<slot />
</RangeCalendarGridRow>
</template>

View File

@ -0,0 +1,21 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarHeadCell, type RangeCalendarHeadCellProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarHeadCellProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarHeadCell :class="cn('w-8 rounded-md text-[0.8rem] font-normal text-muted-foreground', props.class)" v-bind="forwardedProps">
<slot />
</RangeCalendarHeadCell>
</template>

View File

@ -0,0 +1,21 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarHeader, type RangeCalendarHeaderProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarHeaderProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarHeader :class="cn('relative flex w-full items-center justify-between pt-1', props.class)" v-bind="forwardedProps">
<slot />
</RangeCalendarHeader>
</template>

View File

@ -0,0 +1,27 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarHeading, type RangeCalendarHeadingProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarHeadingProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarHeading
v-slot="{ headingValue }"
:class="cn('text-sm font-medium', props.class)"
v-bind="forwardedProps"
>
<slot :heading-value>
{{ headingValue }}
</slot>
</RangeCalendarHeading>
</template>

View File

@ -0,0 +1,32 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarNext, type RangeCalendarNextProps, useForwardProps } from 'radix-vue'
import { ChevronRight } from 'lucide-vue-next'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/lib/registry/default/ui/button'
const props = defineProps<RangeCalendarNextProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarNext
:class="cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
props.class,
)"
v-bind="forwardedProps"
>
<slot>
<ChevronRight class="h-4 w-4" />
</slot>
</RangeCalendarNext>
</template>

View File

@ -0,0 +1,32 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarPrev, type RangeCalendarPrevProps, useForwardProps } from 'radix-vue'
import { ChevronLeft } from 'lucide-vue-next'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/lib/registry/default/ui/button'
const props = defineProps<RangeCalendarPrevProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarPrev
:class="cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
props.class,
)"
v-bind="forwardedProps"
>
<slot>
<ChevronLeft class="h-4 w-4" />
</slot>
</RangeCalendarPrev>
</template>

View File

@ -0,0 +1,12 @@
export { default as RangeCalendar } from './RangeCalendar.vue'
export { default as RangeCalendarCell } from './RangeCalendarCell.vue'
export { default as RangeCalendarCellTrigger } from './RangeCalendarCellTrigger.vue'
export { default as RangeCalendarGrid } from './RangeCalendarGrid.vue'
export { default as RangeCalendarGridBody } from './RangeCalendarGridBody.vue'
export { default as RangeCalendarGridHead } from './RangeCalendarGridHead.vue'
export { default as RangeCalendarGridRow } from './RangeCalendarGridRow.vue'
export { default as RangeCalendarHeadCell } from './RangeCalendarHeadCell.vue'
export { default as RangeCalendarHeader } from './RangeCalendarHeader.vue'
export { default as RangeCalendarHeading } from './RangeCalendarHeading.vue'
export { default as RangeCalendarNextButton } from './RangeCalendarNextButton.vue'
export { default as RangeCalendarPrevButton } from './RangeCalendarPrevButton.vue'

View File

@ -1,7 +1,11 @@
<script setup lang="ts">
import { type Ref, ref } from 'vue'
import { type DateValue, getLocalTimeZone, today } from '@internationalized/date'
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
const value = ref(today(getLocalTimeZone())) as Ref<DateValue>
</script>
<template>
<Calendar class="rounded-md border" />
<Calendar v-model="value" :weekday-format="'short'" class="rounded-md border" />
</template>

View File

@ -1,11 +1,13 @@
<script setup lang="ts">
import { h, ref } from 'vue'
import { DateFormatter, getLocalTimeZone, today } from '@internationalized/date'
import { computed, h, ref } from 'vue'
import { CalendarDate, DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date'
import { toDate } from 'radix-vue'
import { CalendarIcon } from '@radix-icons/vue'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'
import { Calendar } from '@/lib/registry/default/ui/calendar'
import { Button } from '@/lib/registry/default/ui/button'
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormDescription,
@ -13,27 +15,35 @@ import {
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import { toast } from '@/lib/registry/default/ui/toast'
} from '@/lib/registry/new-york/ui/form'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover'
import { toast } from '@/lib/registry/new-york/ui/toast'
import { cn } from '@/lib/utils'
const df = DateFormatter('en-US')
const df = new DateFormatter('en-US', {
dateStyle: 'long',
})
const formSchema = toTypedSchema(z.object({
date: z.date({
required_error: 'A date of birth is required.',
}),
dob: z
.string()
.refine(v => v, { message: 'A date of birth is required.' }),
}))
const value = ref(today(getLocalTimeZone()))
const placeholder = ref()
const { handleSubmit } = useForm({
const { handleSubmit, setValues, values } = useForm({
validationSchema: formSchema,
initialValues: {
date: toDate(value.value, getLocalTimeZone()),
},
})
const value = computed({
get: () => values.dob ? parseDate(values.dob) : undefined,
set: val => val,
})
const onSubmit = handleSubmit((values) => {
toast({
title: 'You submitted the following values:',
@ -43,10 +53,8 @@ const onSubmit = handleSubmit((values) => {
</script>
<template>
<Calendar v-model="value" :weekday-format="'short'" class="rounded-md border" />
<form class="space-y-8" @submit="onSubmit">
<FormField v-slot="{ componentField, value }" name="dob">
<FormField name="dob">
<FormItem class="flex flex-col">
<FormLabel>Date of birth</FormLabel>
<Popover>
@ -58,13 +66,34 @@ const onSubmit = handleSubmit((values) => {
!value && 'text-muted-foreground',
)"
>
<span>{{ value ? df(value!) : "Pick a date" }}</span>
<span>{{ value ? df.format(toDate(value)) : "Pick a date" }}</span>
<CalendarIcon class="ms-auto h-4 w-4 opacity-50" />
</Button>
<input hidden>
</FormControl>
</PopoverTrigger>
<PopoverContent class="p-0">
<Calendar v-bind="componentField" />
<Calendar
v-model:placeholder="placeholder"
v-model="value"
calendar-label="Date of birth"
initial-focus
:min-value="new CalendarDate(1900, 1, 1)"
:max-value="today(getLocalTimeZone())"
@update:model-value="(v) => {
if (v) {
setValues({
dob: v.toString(),
})
}
else {
setValues({
dob: '',
})
}
}"
/>
</PopoverContent>
</Popover>
<FormDescription>

View File

@ -0,0 +1,120 @@
<script setup lang="ts">
import { type HTMLAttributes, type Ref, computed, toRef } from 'vue'
import { CalendarRoot, type CalendarRootEmits, type CalendarRootProps, toDate, useForwardPropsEmits } from 'radix-vue'
import { type DateValue, getLocalTimeZone, today } from '@internationalized/date'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading } from '@/lib/registry/new-york/ui/calendar'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/new-york/ui/select'
import { cn } from '@/lib/utils'
const props = withDefaults(defineProps<CalendarRootProps & { class?: HTMLAttributes['class'] }>(), {
modelValue: undefined,
placeholder() {
return today(getLocalTimeZone())
},
weekdayFormat: 'short',
})
const emits = defineEmits<CalendarRootEmits>()
const delegatedProps = computed(() => {
const { class: _, placeholder: __, ...delegated } = props
return delegated
})
const placeholder = toRef(props.placeholder) as Ref<DateValue>
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<CalendarRoot
v-slot="{ getMonths, getYears, formatter, grid, weekDays }"
v-model:placeholder="placeholder"
v-bind="forwarded"
:class="cn('rounded-md border p-3', props.class)"
>
<CalendarHeader>
<CalendarHeading class="flex w-full items-center justify-between gap-2">
<Select
:default-value="placeholder.month.toString()"
@update:model-value="(v) => {
if (!v || !placeholder) return;
if (Number(v) === placeholder?.month) return;
placeholder = placeholder.set({
month: Number(v),
})
}"
>
<SelectTrigger aria-label="Select month" class="w-[60%]">
<SelectValue placeholder="Select month" />
</SelectTrigger>
<SelectContent class="max-h-[200px]">
<SelectItem
v-for="month in getMonths"
:key="month.toString()" :value="month.month.toString()"
>
{{ formatter.custom(toDate(month), { month: 'long' }) }}
</SelectItem>
</SelectContent>
</Select>
<Select
:default-value="props.placeholder.year.toString()"
@update:model-value="(v) => {
if (!v || !placeholder) return;
if (Number(v) === placeholder?.year) return;
placeholder = placeholder.set({
year: Number(v),
})
}"
>
<SelectTrigger aria-label="Select year" class="w-[40%]">
<SelectValue placeholder="Select year" />
</SelectTrigger>
<SelectContent class="max-h-[200px]">
<SelectItem
v-for="yearValue in getYears({ startIndex: -10, endIndex: 10 })"
:key="yearValue.toString()" :value="yearValue.year.toString()"
>
{{ yearValue.year }}
</SelectItem>
</SelectContent>
</Select>
</CalendarHeading>
</CalendarHeader>
<div class="flex flex-col space-y-4 pt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0">
<CalendarGrid v-for="month in grid" :key="month.value.toString()">
<CalendarGridHead>
<CalendarGridRow class="mb-1 grid w-full grid-cols-7">
<CalendarHeadCell
v-for="day in weekDays" :key="day"
>
{{ day }}
</CalendarHeadCell>
</CalendarGridRow>
</CalendarGridHead>
<CalendarGridBody class="grid">
<CalendarGridRow v-for="(weekDates, index) in month.rows" :key="`weekDate-${index}`" class="grid grid-cols-7">
<CalendarCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
>
<CalendarCellTrigger
:day="weekDate"
:month="month.value"
/>
</CalendarCell>
</CalendarGridRow>
</CalendarGridBody>
</CalendarGrid>
</div>
</CalendarRoot>
</template>

View File

@ -0,0 +1,40 @@
<script setup lang="ts">
import { ref } from 'vue'
import {
DateFormatter,
type DateValue,
getLocalTimeZone,
} from '@internationalized/date'
import { CalendarIcon } from '@radix-icons/vue'
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'long',
})
const value = ref<DateValue>()
</script>
<template>
<Popover>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!value && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
{{ value ? df.format(value.toDate(getLocalTimeZone())) : "Pick a date" }}
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<Calendar v-model="value" initial-focus />
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,109 @@
<script setup lang="ts">
import { computed, h, ref } from 'vue'
import { CalendarDate, DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date'
import { toDate } from 'radix-vue'
import { CalendarIcon } from '@radix-icons/vue'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover'
import { toast } from '@/lib/registry/new-york/ui/toast'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'long',
})
const formSchema = toTypedSchema(z.object({
dob: z
.string()
.refine(v => v, { message: 'A date of birth is required.' }),
}))
const placeholder = ref()
const { handleSubmit, setValues, values } = useForm({
validationSchema: formSchema,
initialValues: {
},
})
const value = computed({
get: () => values.dob ? parseDate(values.dob) : undefined,
set: val => val,
})
const onSubmit = handleSubmit((values) => {
toast({
title: 'You submitted the following values:',
description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),
})
})
</script>
<template>
<form class="space-y-8" @submit="onSubmit">
<FormField name="dob">
<FormItem class="flex flex-col">
<FormLabel>Date of birth</FormLabel>
<Popover>
<PopoverTrigger as-child>
<FormControl>
<Button
variant="outline" :class="cn(
'w-[240px] ps-3 text-start font-normal',
!value && 'text-muted-foreground',
)"
>
<span>{{ value ? df.format(toDate(value)) : "Pick a date" }}</span>
<CalendarIcon class="ms-auto h-4 w-4 opacity-50" />
</Button>
<input hidden>
</FormControl>
</PopoverTrigger>
<PopoverContent class="p-0">
<Calendar
v-model:placeholder="placeholder"
v-model="value"
calendar-label="Date of birth"
initial-focus
:min-value="new CalendarDate(1900, 1, 1)"
:max-value="today(getLocalTimeZone())"
@update:model-value="(v) => {
if (v) {
setValues({
dob: v.toString(),
})
}
else {
setValues({
dob: '',
})
}
}"
/>
</PopoverContent>
</Popover>
<FormDescription>
Your date of birth is used to calculate your age.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</Form>
</template>

View File

@ -0,0 +1,64 @@
<script setup lang="ts">
import { ref } from 'vue'
import {
DateFormatter,
type DateValue,
getLocalTimeZone,
today,
} from '@internationalized/date'
import { CalendarIcon } from '@radix-icons/vue'
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/lib/registry/new-york/ui/select'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'long',
})
const items = [
{ value: 0, label: 'Today' },
{ value: 1, label: 'Tomorrow' },
{ value: 3, label: 'In 3 days' },
{ value: 7, label: 'In a week' },
]
const value = ref<DateValue>()
</script>
<template>
<Popover onfocus>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!value && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
{{ value ? df.format(value.toDate(getLocalTimeZone())) : "Pick a date" }}
</Button>
</PopoverTrigger>
<PopoverContent class="flex w-auto flex-col gap-y-2 p-2">
<Select
@update:model-value="(v) => {
if (!v) return;
value = today(getLocalTimeZone()).add({ days: Number(v) });
}"
>
<SelectTrigger>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="item in items" :key="item.value" :value="item.value.toString()">
{{ item.label }}
</SelectItem>
</SelectContent>
</Select>
<Calendar v-model="value" />
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,52 @@
<script setup lang="ts">
import { type Ref, ref } from 'vue'
import {
CalendarDate,
DateFormatter,
getLocalTimeZone,
} from '@internationalized/date'
import { CalendarIcon } from '@radix-icons/vue'
import type { DateRange } from 'radix-vue'
import { RangeCalendar } from '@/lib/registry/new-york/ui/range-calendar'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover'
import { cn } from '@/lib/utils'
const df = new DateFormatter('en-US', {
dateStyle: 'medium',
})
const value = ref({
start: new CalendarDate(2022, 1, 20),
end: new CalendarDate(2022, 1, 20).add({ days: 20 }),
}) as Ref<DateRange>
</script>
<template>
<Popover>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!value && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="value.start">
<template v-if="value.end">
{{ df.format(value.start.toDate(getLocalTimeZone())) }} - {{ df.format(value.end.toDate(getLocalTimeZone())) }}
</template>
<template v-else>
{{ df.format(value.start.toDate(getLocalTimeZone())) }}
</template>
</template>
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<RangeCalendar v-model="value" initial-focus :number-of-months="2" :placeholder="value?.start" />
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,18 @@
<script setup lang="ts">
import { type Ref, ref } from 'vue'
import { getLocalTimeZone, today } from '@internationalized/date'
import type { DateRange } from 'radix-vue'
import { RangeCalendar } from '@/lib/registry/new-york/ui/range-calendar'
const start = today(getLocalTimeZone())
const end = start.add({ days: 7 })
const value = ref({
start,
end,
}) as Ref<DateRange>
</script>
<template>
<RangeCalendar v-model="value" class="rounded-md border" />
</template>

View File

@ -0,0 +1,60 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarRoot, type RangeCalendarRootEmits, type RangeCalendarRootProps, useForwardPropsEmits } from 'radix-vue'
import { RangeCalendarCell, RangeCalendarCellTrigger, RangeCalendarGrid, RangeCalendarGridBody, RangeCalendarGridHead, RangeCalendarGridRow, RangeCalendarHeadCell, RangeCalendarHeader, RangeCalendarHeading, RangeCalendarNextButton, RangeCalendarPrevButton } from '.'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarRootProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<RangeCalendarRootEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<RangeCalendarRoot
v-slot="{ grid, weekDays }"
:class="cn('p-3', props.class)"
v-bind="forwarded"
>
<RangeCalendarHeader>
<RangeCalendarPrevButton />
<RangeCalendarHeading />
<RangeCalendarNextButton />
</RangeCalendarHeader>
<div class="flex flex-col space-y-4 pt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0">
<RangeCalendarGrid v-for="month in grid" :key="month.value.toString()">
<RangeCalendarGridHead>
<RangeCalendarGridRow class="mb-1 grid w-full grid-cols-7">
<RangeCalendarHeadCell
v-for="day in weekDays" :key="day"
>
{{ day }}
</RangeCalendarHeadCell>
</RangeCalendarGridRow>
</RangeCalendarGridHead>
<RangeCalendarGridBody class="grid">
<RangeCalendarGridRow v-for="(weekDates, index) in month.rows" :key="`weekDate-${index}`" class="grid grid-cols-7">
<RangeCalendarCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
>
<RangeCalendarCellTrigger
:day="weekDate"
:month="month.value"
/>
</RangeCalendarCell>
</RangeCalendarGridRow>
</RangeCalendarGridBody>
</RangeCalendarGrid>
</div>
</RangeCalendarRoot>
</template>

View File

@ -0,0 +1,24 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarCell, type RangeCalendarCellProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarCellProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarCell
:class="cn('relative h-9 w-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:bg-accent first:[&:has([data-selected])]:rounded-l-md last:[&:has([data-selected])]:rounded-r-md [&:has([data-selected][data-outside-month])]:bg-accent/50 [&:has([data-selected][data-selection-end])]:rounded-r-md [&:has([data-selected][data-selection-start])]:rounded-l-md', props.class)"
v-bind="forwardedProps"
>
<slot />
</RangeCalendarCell>
</template>

View File

@ -0,0 +1,40 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarCellTrigger, type RangeCalendarCellTriggerProps, useForwardProps } from 'radix-vue'
import { buttonVariants } from '@/lib/registry/default/ui/button'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarCellTriggerProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarCellTrigger
:class="cn(
buttonVariants({ variant: 'ghost' }),
'h-9 w-9 p-0 font-normal data-[selected]:opacity-100',
'[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground',
// Selection Start
'data-[selection-start]:bg-primary data-[selection-start]:text-primary-foreground data-[selection-start]:hover:bg-primary data-[selection-start]:hover:text-primary-foreground data-[selection-start]:focus:bg-primary data-[selection-start]:focus:text-primary-foreground',
// Selection End
'data-[selection-end]:bg-primary data-[selection-end]:text-primary-foreground data-[selection-end]:hover:bg-primary data-[selection-end]:hover:text-primary-foreground data-[selection-end]:focus:bg-primary data-[selection-end]:focus:text-primary-foreground',
// Outside months
'data-[outside-month]:pointer-events-none data-[outside-month]:text-muted-foreground data-[outside-month]:opacity-50 [&[data-outside-month][data-selected]]:bg-accent/50 [&[data-outside-month][data-selected]]:text-muted-foreground [&[data-outside-month][data-selected]]:opacity-30',
// Disabled
'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',
// Unavailable
'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through',
props.class,
)"
v-bind="forwardedProps"
>
<slot />
</RangeCalendarCellTrigger>
</template>

View File

@ -0,0 +1,24 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarGrid, type RangeCalendarGridProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarGridProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarGrid
:class="cn('w-full border-collapse space-y-1', props.class)"
v-bind="forwardedProps"
>
<slot />
</RangeCalendarGrid>
</template>

View File

@ -0,0 +1,11 @@
<script lang="ts" setup>
import { RangeCalendarGridBody, type RangeCalendarGridBodyProps } from 'radix-vue'
const props = defineProps<RangeCalendarGridBodyProps>()
</script>
<template>
<RangeCalendarGridBody v-bind="props">
<slot />
</RangeCalendarGridBody>
</template>

View File

@ -0,0 +1,11 @@
<script lang="ts" setup>
import { RangeCalendarGridHead, type RangeCalendarGridHeadProps } from 'radix-vue'
const props = defineProps<RangeCalendarGridHeadProps>()
</script>
<template>
<RangeCalendarGridHead v-bind="props">
<slot />
</RangeCalendarGridHead>
</template>

View File

@ -0,0 +1,21 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarGridRow, type RangeCalendarGridRowProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarGridRowProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarGridRow :class="cn('flex mt-2 w-full', props.class)" v-bind="forwardedProps">
<slot />
</RangeCalendarGridRow>
</template>

View File

@ -0,0 +1,21 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarHeadCell, type RangeCalendarHeadCellProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarHeadCellProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarHeadCell :class="cn('w-8 rounded-md text-[0.8rem] font-normal text-muted-foreground', props.class)" v-bind="forwardedProps">
<slot />
</RangeCalendarHeadCell>
</template>

View File

@ -0,0 +1,21 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarHeader, type RangeCalendarHeaderProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarHeaderProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarHeader :class="cn('relative flex w-full items-center justify-between pt-1', props.class)" v-bind="forwardedProps">
<slot />
</RangeCalendarHeader>
</template>

View File

@ -0,0 +1,27 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarHeading, type RangeCalendarHeadingProps, useForwardProps } from 'radix-vue'
import { cn } from '@/lib/utils'
const props = defineProps<RangeCalendarHeadingProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarHeading
v-slot="{ headingValue }"
:class="cn('text-sm font-medium', props.class)"
v-bind="forwardedProps"
>
<slot :heading-value>
{{ headingValue }}
</slot>
</RangeCalendarHeading>
</template>

View File

@ -0,0 +1,32 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarNext, type RangeCalendarNextProps, useForwardProps } from 'radix-vue'
import { ChevronRightIcon } from '@radix-icons/vue'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/lib/registry/default/ui/button'
const props = defineProps<RangeCalendarNextProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarNext
:class="cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
props.class,
)"
v-bind="forwardedProps"
>
<slot>
<ChevronRightIcon class="h-4 w-4" />
</slot>
</RangeCalendarNext>
</template>

View File

@ -0,0 +1,32 @@
<script lang="ts" setup>
import { type HTMLAttributes, computed } from 'vue'
import { RangeCalendarPrev, type RangeCalendarPrevProps, useForwardProps } from 'radix-vue'
import { ChevronLeftIcon } from '@radix-icons/vue'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/lib/registry/default/ui/button'
const props = defineProps<RangeCalendarPrevProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<RangeCalendarPrev
:class="cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
props.class,
)"
v-bind="forwardedProps"
>
<slot>
<ChevronLeftIcon class="h-4 w-4" />
</slot>
</RangeCalendarPrev>
</template>

View File

@ -0,0 +1,12 @@
export { default as RangeCalendar } from './RangeCalendar.vue'
export { default as RangeCalendarCell } from './RangeCalendarCell.vue'
export { default as RangeCalendarCellTrigger } from './RangeCalendarCellTrigger.vue'
export { default as RangeCalendarGrid } from './RangeCalendarGrid.vue'
export { default as RangeCalendarGridBody } from './RangeCalendarGridBody.vue'
export { default as RangeCalendarGridHead } from './RangeCalendarGridHead.vue'
export { default as RangeCalendarGridRow } from './RangeCalendarGridRow.vue'
export { default as RangeCalendarHeadCell } from './RangeCalendarHeadCell.vue'
export { default as RangeCalendarHeader } from './RangeCalendarHeader.vue'
export { default as RangeCalendarHeading } from './RangeCalendarHeading.vue'
export { default as RangeCalendarNextButton } from './RangeCalendarNextButton.vue'
export { default as RangeCalendarPrevButton } from './RangeCalendarPrevButton.vue'

View File

@ -493,6 +493,30 @@
],
"type": "components:ui"
},
{
"name": "range-calendar",
"dependencies": [],
"registryDependencies": [
"utils",
"button"
],
"files": [
"ui/range-calendar/RangeCalendar.vue",
"ui/range-calendar/RangeCalendarCell.vue",
"ui/range-calendar/RangeCalendarCellTrigger.vue",
"ui/range-calendar/RangeCalendarGrid.vue",
"ui/range-calendar/RangeCalendarGridBody.vue",
"ui/range-calendar/RangeCalendarGridHead.vue",
"ui/range-calendar/RangeCalendarGridRow.vue",
"ui/range-calendar/RangeCalendarHeadCell.vue",
"ui/range-calendar/RangeCalendarHeader.vue",
"ui/range-calendar/RangeCalendarHeading.vue",
"ui/range-calendar/RangeCalendarNextButton.vue",
"ui/range-calendar/RangeCalendarPrevButton.vue",
"ui/range-calendar/index.ts"
],
"type": "components:ui"
},
{
"name": "resizable",
"dependencies": [],
@ -762,4 +786,4 @@
],
"type": "components:ui"
}
]
]

View File

@ -28,7 +28,7 @@
},
{
"name": "CalendarGridHead.vue",
"content": "<script lang=\"ts\" setup>\nimport type { HTMLAttributes } from 'vue'\nimport { CalendarGridHead, type CalendarGridHeadProps } from 'radix-vue'\n\nconst props = defineProps<CalendarGridHeadProps>()\n</script>\n\n<template>\n <CalendarGridHead v-bind=\"props\">\n <slot />\n </CalendarGridHead>\n</template>\n"
"content": "<script lang=\"ts\" setup>\nimport { CalendarGridHead, type CalendarGridHeadProps } from 'radix-vue'\n\nconst props = defineProps<CalendarGridHeadProps>()\n</script>\n\n<template>\n <CalendarGridHead v-bind=\"props\">\n <slot />\n </CalendarGridHead>\n</template>\n"
},
{
"name": "CalendarGridRow.vue",
@ -60,4 +60,4 @@
}
],
"type": "components:ui"
}
}

View File

@ -0,0 +1,63 @@
{
"name": "range-calendar",
"dependencies": [],
"registryDependencies": [
"utils",
"button"
],
"files": [
{
"name": "RangeCalendar.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarRoot, type RangeCalendarRootEmits, type RangeCalendarRootProps, useForwardPropsEmits } from 'radix-vue'\nimport { RangeCalendarCell, RangeCalendarCellTrigger, RangeCalendarGrid, RangeCalendarGridBody, RangeCalendarGridHead, RangeCalendarGridRow, RangeCalendarHeadCell, RangeCalendarHeader, RangeCalendarHeading, RangeCalendarNextButton, RangeCalendarPrevButton } from '.'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarRootProps & { class?: HTMLAttributes['class'] }>()\n\nconst emits = defineEmits<RangeCalendarRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <RangeCalendarRoot\n v-slot=\"{ grid, weekDays }\"\n :class=\"cn('p-3', props.class)\"\n v-bind=\"forwarded\"\n >\n <RangeCalendarHeader>\n <RangeCalendarPrevButton />\n <RangeCalendarHeading />\n <RangeCalendarNextButton />\n </RangeCalendarHeader>\n\n <div class=\"flex flex-col space-y-4 pt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0\">\n <RangeCalendarGrid v-for=\"month in grid\" :key=\"month.value.toString()\">\n <RangeCalendarGridHead>\n <RangeCalendarGridRow class=\"mb-1 grid w-full grid-cols-7\">\n <RangeCalendarHeadCell\n v-for=\"day in weekDays\" :key=\"day\"\n >\n {{ day }}\n </RangeCalendarHeadCell>\n </RangeCalendarGridRow>\n </RangeCalendarGridHead>\n <RangeCalendarGridBody class=\"grid\">\n <RangeCalendarGridRow v-for=\"(weekDates, index) in month.rows\" :key=\"`weekDate-${index}`\" class=\"grid grid-cols-7\">\n <RangeCalendarCell\n v-for=\"weekDate in weekDates\"\n :key=\"weekDate.toString()\"\n :date=\"weekDate\"\n >\n <RangeCalendarCellTrigger\n :day=\"weekDate\"\n :month=\"month.value\"\n />\n </RangeCalendarCell>\n </RangeCalendarGridRow>\n </RangeCalendarGridBody>\n </RangeCalendarGrid>\n </div>\n </RangeCalendarRoot>\n</template>\n"
},
{
"name": "RangeCalendarCell.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarCell, type RangeCalendarCellProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarCellProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarCell\n :class=\"cn('relative h-9 w-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:bg-accent first:[&:has([data-selected])]:rounded-l-md last:[&:has([data-selected])]:rounded-r-md [&:has([data-selected][data-outside-month])]:bg-accent/50 [&:has([data-selected][data-selection-end])]:rounded-r-md [&:has([data-selected][data-selection-start])]:rounded-l-md', props.class)\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </RangeCalendarCell>\n</template>\n"
},
{
"name": "RangeCalendarCellTrigger.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarCellTrigger, type RangeCalendarCellTriggerProps, useForwardProps } from 'radix-vue'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarCellTriggerProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarCellTrigger\n :class=\"cn(\n buttonVariants({ variant: 'ghost' }),\n 'h-9 w-9 p-0 font-normal data-[selected]:opacity-100',\n '[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground',\n // Selection Start\n 'data-[selection-start]:bg-primary data-[selection-start]:text-primary-foreground data-[selection-start]:hover:bg-primary data-[selection-start]:hover:text-primary-foreground data-[selection-start]:focus:bg-primary data-[selection-start]:focus:text-primary-foreground',\n // Selection End\n 'data-[selection-end]:bg-primary data-[selection-end]:text-primary-foreground data-[selection-end]:hover:bg-primary data-[selection-end]:hover:text-primary-foreground data-[selection-end]:focus:bg-primary data-[selection-end]:focus:text-primary-foreground',\n // Outside months\n 'data-[outside-month]:pointer-events-none data-[outside-month]:text-muted-foreground data-[outside-month]:opacity-50 [&[data-outside-month][data-selected]]:bg-accent/50 [&[data-outside-month][data-selected]]:text-muted-foreground [&[data-outside-month][data-selected]]:opacity-30',\n // Disabled\n 'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',\n // Unavailable\n 'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through',\n props.class,\n )\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </RangeCalendarCellTrigger>\n</template>\n"
},
{
"name": "RangeCalendarGrid.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarGrid, type RangeCalendarGridProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarGridProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarGrid\n :class=\"cn('w-full border-collapse space-y-1', props.class)\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </RangeCalendarGrid>\n</template>\n"
},
{
"name": "RangeCalendarGridBody.vue",
"content": "<script lang=\"ts\" setup>\nimport { RangeCalendarGridBody, type RangeCalendarGridBodyProps } from 'radix-vue'\n\nconst props = defineProps<RangeCalendarGridBodyProps>()\n</script>\n\n<template>\n <RangeCalendarGridBody v-bind=\"props\">\n <slot />\n </RangeCalendarGridBody>\n</template>\n"
},
{
"name": "RangeCalendarGridHead.vue",
"content": "<script lang=\"ts\" setup>\nimport { RangeCalendarGridHead, type RangeCalendarGridHeadProps } from 'radix-vue'\n\nconst props = defineProps<RangeCalendarGridHeadProps>()\n</script>\n\n<template>\n <RangeCalendarGridHead v-bind=\"props\">\n <slot />\n </RangeCalendarGridHead>\n</template>\n"
},
{
"name": "RangeCalendarGridRow.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarGridRow, type RangeCalendarGridRowProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarGridRowProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarGridRow :class=\"cn('flex mt-2 w-full', props.class)\" v-bind=\"forwardedProps\">\n <slot />\n </RangeCalendarGridRow>\n</template>\n"
},
{
"name": "RangeCalendarHeadCell.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarHeadCell, type RangeCalendarHeadCellProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarHeadCellProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarHeadCell :class=\"cn('w-8 rounded-md text-[0.8rem] font-normal text-muted-foreground', props.class)\" v-bind=\"forwardedProps\">\n <slot />\n </RangeCalendarHeadCell>\n</template>\n"
},
{
"name": "RangeCalendarHeader.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarHeader, type RangeCalendarHeaderProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarHeaderProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarHeader :class=\"cn('relative flex w-full items-center justify-between pt-1', props.class)\" v-bind=\"forwardedProps\">\n <slot />\n </RangeCalendarHeader>\n</template>\n"
},
{
"name": "RangeCalendarHeading.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarHeading, type RangeCalendarHeadingProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarHeadingProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarHeading\n v-slot=\"{ headingValue }\"\n :class=\"cn('text-sm font-medium', props.class)\"\n v-bind=\"forwardedProps\"\n >\n <slot :heading-value>\n {{ headingValue }}\n </slot>\n </RangeCalendarHeading>\n</template>\n"
},
{
"name": "RangeCalendarNextButton.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarNext, type RangeCalendarNextProps, useForwardProps } from 'radix-vue'\nimport { ChevronRight } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\n\nconst props = defineProps<RangeCalendarNextProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarNext\n :class=\"cn(\n buttonVariants({ variant: 'outline' }),\n 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n props.class,\n )\"\n v-bind=\"forwardedProps\"\n >\n <slot>\n <ChevronRight class=\"h-4 w-4\" />\n </slot>\n </RangeCalendarNext>\n</template>\n"
},
{
"name": "RangeCalendarPrevButton.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarPrev, type RangeCalendarPrevProps, useForwardProps } from 'radix-vue'\nimport { ChevronLeft } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\n\nconst props = defineProps<RangeCalendarPrevProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarPrev\n :class=\"cn(\n buttonVariants({ variant: 'outline' }),\n 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n props.class,\n )\"\n v-bind=\"forwardedProps\"\n >\n <slot>\n <ChevronLeft class=\"h-4 w-4\" />\n </slot>\n </RangeCalendarPrev>\n</template>\n"
},
{
"name": "index.ts",
"content": "export { default as RangeCalendar } from './RangeCalendar.vue'\nexport { default as RangeCalendarCell } from './RangeCalendarCell.vue'\nexport { default as RangeCalendarCellTrigger } from './RangeCalendarCellTrigger.vue'\nexport { default as RangeCalendarGrid } from './RangeCalendarGrid.vue'\nexport { default as RangeCalendarGridBody } from './RangeCalendarGridBody.vue'\nexport { default as RangeCalendarGridHead } from './RangeCalendarGridHead.vue'\nexport { default as RangeCalendarGridRow } from './RangeCalendarGridRow.vue'\nexport { default as RangeCalendarHeadCell } from './RangeCalendarHeadCell.vue'\nexport { default as RangeCalendarHeader } from './RangeCalendarHeader.vue'\nexport { default as RangeCalendarHeading } from './RangeCalendarHeading.vue'\nexport { default as RangeCalendarNextButton } from './RangeCalendarNextButton.vue'\nexport { default as RangeCalendarPrevButton } from './RangeCalendarPrevButton.vue'\n"
}
],
"type": "components:ui"
}

View File

@ -0,0 +1,63 @@
{
"name": "range-calendar",
"dependencies": [],
"registryDependencies": [
"utils",
"button"
],
"files": [
{
"name": "RangeCalendar.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarRoot, type RangeCalendarRootEmits, type RangeCalendarRootProps, useForwardPropsEmits } from 'radix-vue'\nimport { RangeCalendarCell, RangeCalendarCellTrigger, RangeCalendarGrid, RangeCalendarGridBody, RangeCalendarGridHead, RangeCalendarGridRow, RangeCalendarHeadCell, RangeCalendarHeader, RangeCalendarHeading, RangeCalendarNextButton, RangeCalendarPrevButton } from '.'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarRootProps & { class?: HTMLAttributes['class'] }>()\n\nconst emits = defineEmits<RangeCalendarRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <RangeCalendarRoot\n v-slot=\"{ grid, weekDays }\"\n :class=\"cn('p-3', props.class)\"\n v-bind=\"forwarded\"\n >\n <RangeCalendarHeader>\n <RangeCalendarPrevButton />\n <RangeCalendarHeading />\n <RangeCalendarNextButton />\n </RangeCalendarHeader>\n\n <div class=\"flex flex-col space-y-4 pt-4 sm:flex-row sm:gap-x-4 sm:gap-y-0\">\n <RangeCalendarGrid v-for=\"month in grid\" :key=\"month.value.toString()\">\n <RangeCalendarGridHead>\n <RangeCalendarGridRow class=\"mb-1 grid w-full grid-cols-7\">\n <RangeCalendarHeadCell\n v-for=\"day in weekDays\" :key=\"day\"\n >\n {{ day }}\n </RangeCalendarHeadCell>\n </RangeCalendarGridRow>\n </RangeCalendarGridHead>\n <RangeCalendarGridBody class=\"grid\">\n <RangeCalendarGridRow v-for=\"(weekDates, index) in month.rows\" :key=\"`weekDate-${index}`\" class=\"grid grid-cols-7\">\n <RangeCalendarCell\n v-for=\"weekDate in weekDates\"\n :key=\"weekDate.toString()\"\n :date=\"weekDate\"\n >\n <RangeCalendarCellTrigger\n :day=\"weekDate\"\n :month=\"month.value\"\n />\n </RangeCalendarCell>\n </RangeCalendarGridRow>\n </RangeCalendarGridBody>\n </RangeCalendarGrid>\n </div>\n </RangeCalendarRoot>\n</template>\n"
},
{
"name": "RangeCalendarCell.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarCell, type RangeCalendarCellProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarCellProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarCell\n :class=\"cn('relative h-9 w-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([data-selected])]:bg-accent first:[&:has([data-selected])]:rounded-l-md last:[&:has([data-selected])]:rounded-r-md [&:has([data-selected][data-outside-month])]:bg-accent/50 [&:has([data-selected][data-selection-end])]:rounded-r-md [&:has([data-selected][data-selection-start])]:rounded-l-md', props.class)\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </RangeCalendarCell>\n</template>\n"
},
{
"name": "RangeCalendarCellTrigger.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarCellTrigger, type RangeCalendarCellTriggerProps, useForwardProps } from 'radix-vue'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarCellTriggerProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarCellTrigger\n :class=\"cn(\n buttonVariants({ variant: 'ghost' }),\n 'h-9 w-9 p-0 font-normal data-[selected]:opacity-100',\n '[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground',\n // Selection Start\n 'data-[selection-start]:bg-primary data-[selection-start]:text-primary-foreground data-[selection-start]:hover:bg-primary data-[selection-start]:hover:text-primary-foreground data-[selection-start]:focus:bg-primary data-[selection-start]:focus:text-primary-foreground',\n // Selection End\n 'data-[selection-end]:bg-primary data-[selection-end]:text-primary-foreground data-[selection-end]:hover:bg-primary data-[selection-end]:hover:text-primary-foreground data-[selection-end]:focus:bg-primary data-[selection-end]:focus:text-primary-foreground',\n // Outside months\n 'data-[outside-month]:pointer-events-none data-[outside-month]:text-muted-foreground data-[outside-month]:opacity-50 [&[data-outside-month][data-selected]]:bg-accent/50 [&[data-outside-month][data-selected]]:text-muted-foreground [&[data-outside-month][data-selected]]:opacity-30',\n // Disabled\n 'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',\n // Unavailable\n 'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through',\n props.class,\n )\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </RangeCalendarCellTrigger>\n</template>\n"
},
{
"name": "RangeCalendarGrid.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarGrid, type RangeCalendarGridProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarGridProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarGrid\n :class=\"cn('w-full border-collapse space-y-1', props.class)\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </RangeCalendarGrid>\n</template>\n"
},
{
"name": "RangeCalendarGridBody.vue",
"content": "<script lang=\"ts\" setup>\nimport { RangeCalendarGridBody, type RangeCalendarGridBodyProps } from 'radix-vue'\n\nconst props = defineProps<RangeCalendarGridBodyProps>()\n</script>\n\n<template>\n <RangeCalendarGridBody v-bind=\"props\">\n <slot />\n </RangeCalendarGridBody>\n</template>\n"
},
{
"name": "RangeCalendarGridHead.vue",
"content": "<script lang=\"ts\" setup>\nimport { RangeCalendarGridHead, type RangeCalendarGridHeadProps } from 'radix-vue'\n\nconst props = defineProps<RangeCalendarGridHeadProps>()\n</script>\n\n<template>\n <RangeCalendarGridHead v-bind=\"props\">\n <slot />\n </RangeCalendarGridHead>\n</template>\n"
},
{
"name": "RangeCalendarGridRow.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarGridRow, type RangeCalendarGridRowProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarGridRowProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarGridRow :class=\"cn('flex mt-2 w-full', props.class)\" v-bind=\"forwardedProps\">\n <slot />\n </RangeCalendarGridRow>\n</template>\n"
},
{
"name": "RangeCalendarHeadCell.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarHeadCell, type RangeCalendarHeadCellProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarHeadCellProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarHeadCell :class=\"cn('w-8 rounded-md text-[0.8rem] font-normal text-muted-foreground', props.class)\" v-bind=\"forwardedProps\">\n <slot />\n </RangeCalendarHeadCell>\n</template>\n"
},
{
"name": "RangeCalendarHeader.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarHeader, type RangeCalendarHeaderProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarHeaderProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarHeader :class=\"cn('relative flex w-full items-center justify-between pt-1', props.class)\" v-bind=\"forwardedProps\">\n <slot />\n </RangeCalendarHeader>\n</template>\n"
},
{
"name": "RangeCalendarHeading.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarHeading, type RangeCalendarHeadingProps, useForwardProps } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<RangeCalendarHeadingProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarHeading\n v-slot=\"{ headingValue }\"\n :class=\"cn('text-sm font-medium', props.class)\"\n v-bind=\"forwardedProps\"\n >\n <slot :heading-value>\n {{ headingValue }}\n </slot>\n </RangeCalendarHeading>\n</template>\n"
},
{
"name": "RangeCalendarNextButton.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarNext, type RangeCalendarNextProps, useForwardProps } from 'radix-vue'\nimport { ChevronRightIcon } from '@radix-icons/vue'\nimport { cn } from '@/lib/utils'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\n\nconst props = defineProps<RangeCalendarNextProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarNext\n :class=\"cn(\n buttonVariants({ variant: 'outline' }),\n 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n props.class,\n )\"\n v-bind=\"forwardedProps\"\n >\n <slot>\n <ChevronRightIcon class=\"h-4 w-4\" />\n </slot>\n </RangeCalendarNext>\n</template>\n"
},
{
"name": "RangeCalendarPrevButton.vue",
"content": "<script lang=\"ts\" setup>\nimport { type HTMLAttributes, computed } from 'vue'\nimport { RangeCalendarPrev, type RangeCalendarPrevProps, useForwardProps } from 'radix-vue'\nimport { ChevronLeftIcon } from '@radix-icons/vue'\nimport { cn } from '@/lib/utils'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\n\nconst props = defineProps<RangeCalendarPrevProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RangeCalendarPrev\n :class=\"cn(\n buttonVariants({ variant: 'outline' }),\n 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n props.class,\n )\"\n v-bind=\"forwardedProps\"\n >\n <slot>\n <ChevronLeftIcon class=\"h-4 w-4\" />\n </slot>\n </RangeCalendarPrev>\n</template>\n"
},
{
"name": "index.ts",
"content": "export { default as RangeCalendar } from './RangeCalendar.vue'\nexport { default as RangeCalendarCell } from './RangeCalendarCell.vue'\nexport { default as RangeCalendarCellTrigger } from './RangeCalendarCellTrigger.vue'\nexport { default as RangeCalendarGrid } from './RangeCalendarGrid.vue'\nexport { default as RangeCalendarGridBody } from './RangeCalendarGridBody.vue'\nexport { default as RangeCalendarGridHead } from './RangeCalendarGridHead.vue'\nexport { default as RangeCalendarGridRow } from './RangeCalendarGridRow.vue'\nexport { default as RangeCalendarHeadCell } from './RangeCalendarHeadCell.vue'\nexport { default as RangeCalendarHeader } from './RangeCalendarHeader.vue'\nexport { default as RangeCalendarHeading } from './RangeCalendarHeading.vue'\nexport { default as RangeCalendarNextButton } from './RangeCalendarNextButton.vue'\nexport { default as RangeCalendarPrevButton } from './RangeCalendarPrevButton.vue'\n"
}
],
"type": "components:ui"
}