diff --git a/apps/www/__registry__/index.ts b/apps/www/__registry__/index.ts index 08289ff8..2c7ae3aa 100644 --- a/apps/www/__registry__/index.ts +++ b/apps/www/__registry__/index.ts @@ -506,6 +506,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'], }, + RangePickerWithSlot: { + name: 'RangePickerWithSlot', + type: 'components:example', + registryDependencies: ['utils', 'button', 'calendar', 'popover'], + component: () => import('../src/lib/registry/default/example/RangePickerWithSlot.vue').then(m => m.default), + files: ['../src/lib/registry/default/example/RangePickerWithSlot.vue'], + }, ScrollAreaDemo: { name: 'ScrollAreaDemo', type: 'components:example', @@ -1390,6 +1397,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'], }, + RangePickerWithSlot: { + name: 'RangePickerWithSlot', + type: 'components:example', + registryDependencies: ['utils', 'button', 'calendar', 'popover'], + component: () => import('../src/lib/registry/new-york/example/RangePickerWithSlot.vue').then(m => m.default), + files: ['../src/lib/registry/new-york/example/RangePickerWithSlot.vue'], + }, ScrollAreaDemo: { name: 'ScrollAreaDemo', type: 'components:example', diff --git a/apps/www/src/content/docs/components/calendar.md b/apps/www/src/content/docs/components/calendar.md index ccdc9971..ab0dff47 100644 --- a/apps/www/src/content/docs/components/calendar.md +++ b/apps/www/src/content/docs/components/calendar.md @@ -56,5 +56,40 @@ import { Calendar } from '@/components/ui/calendar' ``` -See the [VCalendar](https://vcalendar.io/getting-started/installation.html) documentation for more information. +The API is essentially the same, i.e. props and slots. See the [VCalendar](https://vcalendar.io/getting-started/installation.html) documentation for more information. +### Slots + +The slots available are [those currently supported](https://github.com/nathanreyes/v-calendar/blob/v3.1.2/src/components/Calendar/CalendarSlot.vue#L16-L28) by VCalendar, namely : + +- `day-content` +- `day-popover` +- `dp-footer` +- `footer` +- `header-title-wrapper` +- `header-title` +- `header-prev-button` +- `header-next-button` +- `nav` +- `nav-prev-button` +- `nav-next-button` +- `page` +- `time-header` + +Example using the `day-content` slot: + +```vue + + + + + + + {{ day.label }} + + + + +``` \ No newline at end of file diff --git a/apps/www/src/content/docs/components/date-picker.md b/apps/www/src/content/docs/components/date-picker.md index d2070ad2..3fbdc563 100644 --- a/apps/www/src/content/docs/components/date-picker.md +++ b/apps/www/src/content/docs/components/date-picker.md @@ -72,6 +72,10 @@ const date = ref() +### With Slot + + + ### Form diff --git a/apps/www/src/lib/registry/default/example/RangePickerWithSlot.vue b/apps/www/src/lib/registry/default/example/RangePickerWithSlot.vue new file mode 100644 index 00000000..be4ab976 --- /dev/null +++ b/apps/www/src/lib/registry/default/example/RangePickerWithSlot.vue @@ -0,0 +1,69 @@ + + + + + + + + + + + {{ date.start ? ( + date.end ? `${format(date.start, 'LLL dd, y')} - ${format(date.end, 'LLL dd, y')}` + : format(date.start, 'LLL dd, y') + ) : 'Pick a date' }} + + + + + + + + Entry time + + Exit time + + + + + + + + diff --git a/apps/www/src/lib/registry/default/ui/calendar/Calendar.vue b/apps/www/src/lib/registry/default/ui/calendar/Calendar.vue index 9415ce64..f3c11d83 100644 --- a/apps/www/src/lib/registry/default/ui/calendar/Calendar.vue +++ b/apps/www/src/lib/registry/default/ui/calendar/Calendar.vue @@ -3,7 +3,8 @@ import { useVModel } from '@vueuse/core' import type { Calendar } from 'v-calendar' import { DatePicker } from 'v-calendar' import { ChevronLeft, ChevronRight } from 'lucide-vue-next' -import { computed, nextTick, onMounted, ref } from 'vue' +import { computed, nextTick, onMounted, ref, useSlots } from 'vue' +import { isVCalendarSlot } from '.' import { buttonVariants } from '@/lib/registry/default/ui/button' import { cn } from '@/lib/utils' @@ -64,6 +65,16 @@ onMounted(async () => { if (modelValue.value instanceof Date && calendarRef.value) calendarRef.value.focusDate(modelValue.value) }) + +const $slots = useSlots() +const vCalendarSlots = computed(() => { + return Object.keys($slots) + .filter(name => isVCalendarSlot(name)) + .reduce((obj: Record, key: string) => { + obj[key] = $slots[key] + return obj + }, {}) +}) @@ -86,7 +97,11 @@ onMounted(async () => { trim-weeks :transition="'none'" :columns="columns" - /> + > + + + + diff --git a/apps/www/src/lib/registry/default/ui/calendar/index.ts b/apps/www/src/lib/registry/default/ui/calendar/index.ts index 50f21114..d17d00f2 100644 --- a/apps/www/src/lib/registry/default/ui/calendar/index.ts +++ b/apps/www/src/lib/registry/default/ui/calendar/index.ts @@ -1 +1,22 @@ export { default as Calendar } from './Calendar.vue' +import type { CalendarSlotName } from 'v-calendar/dist/types/src/components/Calendar/CalendarSlot.vue.d.ts' + +export function isVCalendarSlot(slotName: string): slotName is CalendarSlotName { + const validSlots: CalendarSlotName[] = [ + 'day-content', + 'day-popover', + 'dp-footer', + 'footer', + 'header-title-wrapper', + 'header-title', + 'header-prev-button', + 'header-next-button', + 'nav', + 'nav-prev-button', + 'nav-next-button', + 'page', + 'time-header', + ] + + return validSlots.includes(slotName as CalendarSlotName) +} diff --git a/apps/www/src/lib/registry/new-york/example/RangePickerWithSlot.vue b/apps/www/src/lib/registry/new-york/example/RangePickerWithSlot.vue new file mode 100644 index 00000000..95dcd021 --- /dev/null +++ b/apps/www/src/lib/registry/new-york/example/RangePickerWithSlot.vue @@ -0,0 +1,73 @@ + + + + + + + + + + + {{ date.start ? ( + date.end ? `${format(date.start, 'LLL dd, y')} - ${format(date.end, 'LLL dd, y')}` + : format(date.start, 'LLL dd, y') + ) : 'Pick a date' }} + + + + + + + + + Entry time + + + + Exit time + + + + + + + + + diff --git a/apps/www/src/lib/registry/new-york/ui/calendar/Calendar.vue b/apps/www/src/lib/registry/new-york/ui/calendar/Calendar.vue index 182ad770..f5241ea2 100644 --- a/apps/www/src/lib/registry/new-york/ui/calendar/Calendar.vue +++ b/apps/www/src/lib/registry/new-york/ui/calendar/Calendar.vue @@ -3,7 +3,8 @@ import { useVModel } from '@vueuse/core' import type { Calendar } from 'v-calendar' import { DatePicker } from 'v-calendar' import { ChevronLeftIcon, ChevronRightIcon } from '@radix-icons/vue' -import { computed, nextTick, onMounted, ref } from 'vue' +import { computed, nextTick, onMounted, ref, useSlots } from 'vue' +import { isVCalendarSlot } from '.' import { buttonVariants } from '@/lib/registry/new-york/ui/button' import { cn } from '@/lib/utils' @@ -63,6 +64,16 @@ onMounted(async () => { if (modelValue.value instanceof Date && calendarRef.value) calendarRef.value.focusDate(modelValue.value) }) + +const $slots = useSlots() +const vCalendarSlots = computed(() => { + return Object.keys($slots) + .filter(name => isVCalendarSlot(name)) + .reduce((obj: Record, key: string) => { + obj[key] = $slots[key] + return obj + }, {}) +}) @@ -85,7 +96,11 @@ onMounted(async () => { trim-weeks :transition="'none'" :columns="columns" - /> + > + + + + diff --git a/apps/www/src/lib/registry/new-york/ui/calendar/index.ts b/apps/www/src/lib/registry/new-york/ui/calendar/index.ts index 50f21114..d17d00f2 100644 --- a/apps/www/src/lib/registry/new-york/ui/calendar/index.ts +++ b/apps/www/src/lib/registry/new-york/ui/calendar/index.ts @@ -1 +1,22 @@ export { default as Calendar } from './Calendar.vue' +import type { CalendarSlotName } from 'v-calendar/dist/types/src/components/Calendar/CalendarSlot.vue.d.ts' + +export function isVCalendarSlot(slotName: string): slotName is CalendarSlotName { + const validSlots: CalendarSlotName[] = [ + 'day-content', + 'day-popover', + 'dp-footer', + 'footer', + 'header-title-wrapper', + 'header-title', + 'header-prev-button', + 'header-next-button', + 'nav', + 'nav-prev-button', + 'nav-next-button', + 'page', + 'time-header', + ] + + return validSlots.includes(slotName as CalendarSlotName) +} diff --git a/apps/www/src/public/registry/styles/default/calendar.json b/apps/www/src/public/registry/styles/default/calendar.json index e8f631e2..bae081a3 100644 --- a/apps/www/src/public/registry/styles/default/calendar.json +++ b/apps/www/src/public/registry/styles/default/calendar.json @@ -11,11 +11,11 @@ "files": [ { "name": "Calendar.vue", - "content": "\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n\n\n\n" + "content": "\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n\n\n\n" }, { "name": "index.ts", - "content": "export { default as Calendar } from './Calendar.vue'\n" + "content": "export { default as Calendar } from './Calendar.vue'\nimport type { CalendarSlotName } from 'v-calendar/dist/types/src/components/Calendar/CalendarSlot.vue.d.ts'\n\nexport function isVCalendarSlot(slotName: string): slotName is CalendarSlotName {\n const validSlots: CalendarSlotName[] = [\n 'day-content',\n 'day-popover',\n 'dp-footer',\n 'footer',\n 'header-title-wrapper',\n 'header-title',\n 'header-prev-button',\n 'header-next-button',\n 'nav',\n 'nav-prev-button',\n 'nav-next-button',\n 'page',\n 'time-header',\n ]\n\n return validSlots.includes(slotName as CalendarSlotName)\n}\n" } ], "type": "components:ui" diff --git a/apps/www/src/public/registry/styles/new-york/calendar.json b/apps/www/src/public/registry/styles/new-york/calendar.json index b83d724f..3adbb0b1 100644 --- a/apps/www/src/public/registry/styles/new-york/calendar.json +++ b/apps/www/src/public/registry/styles/new-york/calendar.json @@ -11,11 +11,11 @@ "files": [ { "name": "Calendar.vue", - "content": "\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n\n\n\n" + "content": "\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n\n\n\n" }, { "name": "index.ts", - "content": "export { default as Calendar } from './Calendar.vue'\n" + "content": "export { default as Calendar } from './Calendar.vue'\nimport type { CalendarSlotName } from 'v-calendar/dist/types/src/components/Calendar/CalendarSlot.vue.d.ts'\n\nexport function isVCalendarSlot(slotName: string): slotName is CalendarSlotName {\n const validSlots: CalendarSlotName[] = [\n 'day-content',\n 'day-popover',\n 'dp-footer',\n 'footer',\n 'header-title-wrapper',\n 'header-title',\n 'header-prev-button',\n 'header-next-button',\n 'nav',\n 'nav-prev-button',\n 'nav-next-button',\n 'page',\n 'time-header',\n ]\n\n return validSlots.includes(slotName as CalendarSlotName)\n}\n" } ], "type": "components:ui"