feat: update
This commit is contained in:
parent
f6a3879582
commit
6795b8fdfa
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
|||
38
apps/www/src/content/docs/components/date-picker.md
Normal file
38
apps/www/src/content/docs/components/date-picker.md
Normal 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" />
|
||||
18
apps/www/src/content/docs/components/range-calendar.md
Normal file
18
apps/www/src/content/docs/components/range-calendar.md
Normal 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
|
||||
```
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: Date Picker
|
||||
title: VCalendar Date Picker
|
||||
description: A date picker component with range and presets.
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
40
apps/www/src/lib/registry/default/example/DatePickerDemo.vue
Normal file
40
apps/www/src/lib/registry/default/example/DatePickerDemo.vue
Normal 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>
|
||||
109
apps/www/src/lib/registry/default/example/DatePickerForm.vue
Normal file
109
apps/www/src/lib/registry/default/example/DatePickerForm.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { CalendarGridHead, type CalendarGridHeadProps } from 'radix-vue'
|
||||
|
||||
const props = defineProps<CalendarGridHeadProps>()
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
12
apps/www/src/lib/registry/default/ui/range-calendar/index.ts
Normal file
12
apps/www/src/lib/registry/default/ui/range-calendar/index.ts
Normal 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'
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
109
apps/www/src/lib/registry/new-york/example/DatePickerForm.vue
Normal file
109
apps/www/src/lib/registry/new-york/example/DatePickerForm.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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'
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user