Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Calendar): implement component #2618

Merged
merged 77 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
60ddf41
feat(calendar): implement component
hywax Nov 12, 2024
8edd8f2
feat(Calendar): base struct
hywax Nov 13, 2024
fc9d69b
feat(Calendar): style
hywax Nov 13, 2024
e2e78b1
Merge branch 'v3' into radix-calendar
hywax Nov 13, 2024
0ebafb5
feat(Calendar): multi
hywax Nov 13, 2024
62e3f63
feat(Calendar): fix color
hywax Nov 13, 2024
975df20
feat(Calendar): natural headCell
hywax Nov 13, 2024
5a5680d
feat(Calendar): playground
hywax Nov 13, 2024
e0f40fa
feat(Calendar): update
hywax Nov 13, 2024
2a12716
feat(Calendar): update
hywax Nov 13, 2024
d54d5e2
Merge branch 'v3' into radix-calendar
hywax Nov 14, 2024
20532bf
feat(Calendar): component
hywax Nov 14, 2024
f7e58c9
feat(Calendar): style
hywax Nov 15, 2024
01c967c
Merge branch 'v3' into radix-calendar
hywax Nov 15, 2024
66f8078
feat(Calendar): to native `Date`
hywax Nov 15, 2024
4b35059
feat(Calendar): prepare docs
hywax Nov 15, 2024
cd0ba13
feat(Calendar): range
hywax Nov 15, 2024
b80efc2
feat(Calendar): minValue, maxValue
hywax Nov 15, 2024
89b8bde
feat(Calendar): add issue
hywax Nov 15, 2024
2776405
feat(Calendar): defaultValue
hywax Nov 15, 2024
99cdb83
feat(Calendar): date
hywax Nov 15, 2024
14ec31e
feat(Calendar): model
hywax Nov 15, 2024
b3ab240
feat(Calendar): tests
hywax Nov 15, 2024
330bc8d
feat(Calendar): locale
hywax Nov 17, 2024
780641a
feat(ColorPicker): fix
hywax Nov 18, 2024
84ef6e2
feat(ColorPicker): fix 2
hywax Nov 18, 2024
22913dd
feat(ColorPicker): fix 3
hywax Nov 18, 2024
5fa1cbe
feat(ColorPicker): fix 4
hywax Nov 18, 2024
c0f4680
feat(ColorPicker): fix 5
hywax Nov 18, 2024
479b369
Merge branch 'v3' into radix-calendar
hywax Nov 18, 2024
42c9e7a
feat(ColorPicker): fix 6
hywax Nov 18, 2024
2af16b5
feat(ColorPicker): fix 7
hywax Nov 18, 2024
af5ef66
feat(ColorPicker): fix 8
hywax Nov 18, 2024
71541ec
feat(ColorPicker): docs
hywax Nov 18, 2024
90f4770
Merge branch 'v3' into radix-calendar
hywax Nov 19, 2024
75540cb
feat(ColorPicker): add pl lang
hywax Nov 19, 2024
bc1b475
Merge branch 'v3' into radix-calendar
hywax Nov 19, 2024
e0f728d
feat(Calendar): add fa-IR lang
hywax Nov 19, 2024
442da0e
Merge branch 'v3' into radix-calendar
benjamincanac Nov 21, 2024
4565f89
test: improve
benjamincanac Nov 21, 2024
b699546
docs: clean
benjamincanac Nov 21, 2024
889692f
chore(Calendar): clean
benjamincanac Nov 21, 2024
7fad7a0
feat(ColorPicker): unused style
hywax Nov 21, 2024
63c9239
feat(ColorPicker): disabled
hywax Nov 21, 2024
de98e8d
feat(ColorPicker): fix
hywax Nov 21, 2024
f368ca8
feat(ColorPicker): snap
hywax Nov 21, 2024
571c891
feat(ColorPicker): KO
hywax Nov 21, 2024
f11e25e
feat(ColorPicker): fix
hywax Nov 21, 2024
30e2442
Merge branch 'v3' into radix-calendar
hywax Nov 21, 2024
299bfb0
feat(ColorPicker): example picker
hywax Nov 21, 2024
47c1d8b
Merge branch 'v3' into radix-calendar
hywax Nov 21, 2024
061dee4
feat(ColorPicker): tr
hywax Nov 21, 2024
d85dbb7
feat(ColorPicker): range
hywax Nov 21, 2024
0b24a63
feat(ColorPicker): fix
hywax Nov 21, 2024
4785fd2
feat(Calendar): global update
hywax Nov 21, 2024
d4bdcc4
feat(Calendar): remove unused
hywax Nov 21, 2024
dd264bb
feat(Calendar): clear
hywax Nov 21, 2024
ee422ee
fix(Calendar): duplicate $emit update:modelValue
hywax Nov 21, 2024
ac49cc5
fix(Calendar): docs
hywax Nov 21, 2024
91af712
fix(Calendar): use `dir`, `locale` from useLocale
hywax Nov 21, 2024
d56f1f7
docs(Calendar): examples
hywax Nov 22, 2024
86fb989
Merge branch 'v3' into radix-calendar
hywax Nov 22, 2024
97782c2
Merge branch 'v3' into radix-calendar
hywax Nov 23, 2024
6e0bc61
feat(ColorPicker): nl locale
hywax Nov 23, 2024
dba26eb
Merge branch 'v3' into radix-calendar
hywax Nov 25, 2024
84c4ae3
Merge branch 'v3' into radix-calendar
hywax Nov 25, 2024
796901e
Merge branch 'v3' into radix-calendar
hywax Nov 25, 2024
ba2f728
fix deps
hywax Nov 25, 2024
443128a
merge remote
hywax Nov 25, 2024
290a9ed
Merge branch 'v3' into radix-calendar
benjamincanac Nov 25, 2024
2a1c304
up
benjamincanac Nov 25, 2024
3c4a2ac
up
benjamincanac Nov 25, 2024
ba9ddba
up
benjamincanac Nov 26, 2024
7e61104
up
benjamincanac Nov 26, 2024
f7b4158
eat(Calendar): fix
hywax Nov 26, 2024
80577f1
Merge remote-tracking branch 'origin/radix-calendar' into radix-calendar
hywax Nov 26, 2024
873a469
feat(Calendar): fix 2
hywax Nov 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/content/3.components/calendar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
description:
links:
- label: Calendar
icon: i-custom-radix-vue
to: https://www.radix-vue.com/components/calendar.html
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Calendar.vue
---

## Usage

## Examples

## API

### Props

:component-props

### Slots

:component-slots

### Emits

:component-emits

## Theme

:component-theme
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
},
"dependencies": {
"@iconify/vue": "^4.1.2",
"@internationalized/date": "^3.5.6",
"@nuxt/devtools-kit": "^1.6.0",
"@nuxt/fonts": "^0.10.2",
"@nuxt/icon": "^1.7.2",
Expand Down
1 change: 1 addition & 0 deletions playground/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const components = [
'button',
'button-group',
'card',
'calendar',
'carousel',
'checkbox',
'chip',
Expand Down
32 changes: 32 additions & 0 deletions playground/app/pages/components/calendar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script setup lang="ts">
import theme from '#build/ui/calendar'

const colors = Object.keys(theme.variants.color) as Array<keyof typeof theme.variants.color>
const sizes = Object.keys(theme.variants.size) as Array<keyof typeof theme.variants.size>

const value = ref<Date>(new Date())
</script>

<template>
<div class="flex flex-col gap-4">
<div class="flex justify-center gap-2">
<UCalendar v-model="value" />
</div>
<div class="flex items-center gap-4">
<UCalendar
v-for="color in colors"
:key="color"
v-model="value"
:color="color"
/>
</div>
<div class="flex items-center gap-4">
<UCalendar
v-for="size in sizes"
:key="size"
v-model="value"
:size="size"
/>
</div>
</div>
</template>
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

117 changes: 117 additions & 0 deletions src/runtime/components/Calendar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<script lang="ts">
import { computed } from 'vue'
import { tv, type VariantProps } from 'tailwind-variants'
import type { CalendarRootProps, CalendarRootEmits, CalendarCellTriggerProps } from 'radix-vue'
import type { AppConfig } from '@nuxt/schema'
import _appConfig from '#build/app.config'
import theme from '#build/ui/calendar'

const appConfig = _appConfig as AppConfig & { ui: { calendar: Partial<typeof theme> } }

const calendar = tv({ extend: tv(theme), ...(appConfig.ui?.calendar || {}) })

type CalendarVariants = VariantProps<typeof calendar>

export type CalendarProps = CalendarRootProps & {
color?: CalendarVariants['color']
size?: CalendarVariants['size']
class?: any
ui?: Partial<typeof calendar.slots>
}

export interface CalendarEmits extends CalendarRootEmits {}

export interface CalendarSlots {
'heading': (props: { value: string }) => any
'day': (props: Pick<CalendarCellTriggerProps, 'day'>) => any
'week-day': (props: { day: string }) => any
}
</script>

<script setup lang="ts">
import { useForwardPropsEmits, CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'radix-vue'
import { reactivePick } from '@vueuse/core'
import UButton from './Button.vue'
// import { useLocale } from '../composables/useLocale'

const props = withDefaults(defineProps<CalendarProps>(), {
fixedWeeks: true
})
const emits = defineEmits<CalendarEmits>()
defineSlots<CalendarSlots>()

// const { locale, dir } = useLocale()
const _rootProps = useForwardPropsEmits(reactivePick(props, 'defaultValue', 'modelValue'), emits)

const ui = computed(() => calendar({
color: props.color,
size: props.size
}))
</script>

<template>
<CalendarRoot
v-slot="{ weekDays, grid }"
:class="ui.root({ class: [props.class, props.ui?.root] })"
fixed-weeks
>
<CalendarHeader :class="ui.header({ class: props.ui?.header })">
<CalendarPrev as-child>
<UButton :icon="appConfig.ui.icons.chevronLeft" :size="props.size" color="neutral" variant="ghost" />
</CalendarPrev>
<CalendarHeading v-slot="{ headingValue }" :class="ui.heading({ class: props.ui?.heading })">
<slot name="heading" :value="headingValue">
{{ headingValue }}
</slot>
</CalendarHeading>
<CalendarNext as-child>
<UButton :icon="appConfig.ui.icons.chevronRight" :size="props.size" color="neutral" variant="ghost" />
</CalendarNext>
</CalendarHeader>
<div :class="ui.body({ class: props.ui?.body })">
<CalendarGrid
v-for="month in grid"
:key="month.value.toString()"
:class="ui.grid({ class: props.ui?.grid })"
>
<CalendarGridHead>
<CalendarGridRow :class="ui.gridWeekDaysRow({ class: props.ui?.gridWeekDaysRow })">
<CalendarHeadCell
v-for="day in weekDays"
:key="day"
:class="ui.headCell({ class: props.ui?.headCell })"
>
<slot name="week-day" :day="day">
{{ day }}
</slot>
</CalendarHeadCell>
</CalendarGridRow>
</CalendarGridHead>
<CalendarGridBody :class="ui.gridBody({ class: props.ui?.gridBody })">
<CalendarGridRow
v-for="(weekDates, index) in month.rows"
:key="`weekDate-${index}`"
:class="ui.gridRow({ class: props.ui?.gridRow })"
>
<CalendarCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
:class="ui.cell({ class: props.ui?.cell })"
>
<CalendarCellTrigger
:day="weekDate"
:month="month.value"
:class="ui.cellTrigger({ class: props.ui?.cellTrigger })"
>
<slot name="day" :day="weekDate">
{{ weekDate.day }}
</slot>
</CalendarCellTrigger>
</CalendarCell>
</CalendarGridRow>
</CalendarGridBody>
</CalendarGrid>
</div>
</CalendarRoot>
</template>
1 change: 1 addition & 0 deletions src/runtime/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from '../components/AvatarGroup.vue'
export * from '../components/Badge.vue'
export * from '../components/Breadcrumb.vue'
export * from '../components/Button.vue'
export * from '../components/Calendar.vue'
export * from '../components/Card.vue'
export * from '../components/Carousel.vue'
export * from '../components/Checkbox.vue'
Expand Down
66 changes: 66 additions & 0 deletions src/theme/calendar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { ModuleOptions } from '../module'

export default (options: Required<ModuleOptions>) => {
return {
slots: {
root: 'rounded-[calc(var(--ui-radius)*1.5)]',
hywax marked this conversation as resolved.
Show resolved Hide resolved
header: 'flex items-center justify-between',
body: 'flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0',
benjamincanac marked this conversation as resolved.
Show resolved Hide resolved
heading: 'text-sm font-medium',
grid: 'w-full border-collapse select-none space-y-1',
gridRow: 'grid grid-cols-7',
gridWeekDaysRow: 'mb-1 grid w-full grid-cols-7',
gridBody: 'grid',
headCell: 'rounded-md text-xs',
cell: 'relative text-center text-sm',
hywax marked this conversation as resolved.
Show resolved Hide resolved
cellTrigger: ['relative flex items-center justify-center rounded-full whitespace-nowrap outline-none focus-visible:ring-2 focus-visible:ring-inset data-[disabled]:text-[var(--ui-text)]/30 data-[selected]:text-[var(--ui-bg)] hover:bg-[var(--ui-bg-elevated)]', options.theme.transitions && 'transition-[color,opacity] duration-200']
},
variants: {
color: {
...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, {
headCell: `text-[var(--ui-${color})]`,
cellTrigger: `focus-visible:ring-[var(--ui-${color})] data-[selected]:!bg-[var(--ui-${color})] data-[today]:bg-[var(--ui-${color})]/10`
hywax marked this conversation as resolved.
Show resolved Hide resolved
}])),
neutral: {
cellTrigger: ''
}
},
size: {
xs: {
heading: 'text-xs',
cell: 'text-xs',
headCell: 'text-[10px]',
cellTrigger: 'w-7 h-7',
body: 'space-y-2 pt-2'
},
sm: {
heading: 'text-xs',
cell: 'text-xs',
cellTrigger: 'w-7 h-7'
},
md: {
cellTrigger: 'w-8 h-8'
},
lg: {
heading: 'text-md',
headCell: 'text-md',
cellTrigger: 'w-9 h-9 text-md'
},
xl: {
heading: 'text-lg',
headCell: 'text-lg',
cellTrigger: 'w-10 h-10 text-lg'
}
}
},
compoundVariants: [
...(options.theme.colors || []).map((color: string) => ({
color
}))
],
defaultVariants: {
size: 'md',
color: 'primary'
}
}
}
1 change: 1 addition & 0 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { default as badge } from './badge'
export { default as breadcrumb } from './breadcrumb'
export { default as button } from './button'
export { default as buttonGroup } from './button-group'
export { default as calendar } from './calendar'
export { default as card } from './card'
export { default as carousel } from './carousel'
export { default as checkbox } from './checkbox'
Expand Down
17 changes: 17 additions & 0 deletions test/components/Calendar.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, it, expect } from 'vitest'
import Calendar, { type CalendarProps, type CalendarSlots } from '../../src/runtime/components/Calendar.vue'
import ComponentRender from '../component-render'

describe('Calendar', () => {
it.each([
// Props
['with as', { props: { as: 'div' } }],
['with class', { props: { class: '' } }],
['with ui', { props: { ui: {} } }],
// Slots
['with default slot', { slots: { default: () => 'Default slot' } }]
])('renders %s correctly', async (nameOrHtml: string, options: { props?: CalendarProps, slots?: Partial<CalendarSlots> }) => {

Check failure on line 13 in test/components/Calendar.spec.ts

View workflow job for this annotation

GitHub Actions / ci (ubuntu-latest, 20)

Argument of type '(nameOrHtml: string, options: { props?: CalendarProps; slots?: Partial<CalendarSlots>; }) => Promise<void>' is not assignable to parameter of type '(...args: [string, { props: { as: string; }; }] | [string, { props: { class: string; }; }] | [string, { props: { ui: {}; }; }] | [string, { slots: { default: () => "Default slot"; }; }]) => Awaitable<void>'.
const html = await ComponentRender(nameOrHtml, options, Calendar)
expect(html).toMatchSnapshot()
})
})
Loading