Skip to content

Commit

Permalink
fix(calendar): add missing first-day-of-week property support (#20096)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnleider committed Jul 9, 2024
1 parent 34aa0e0 commit 77af0c6
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export const VDatePickerMonth = genericComponent<VDatePickerMonthSlots>()({
key={ daysInMonth.value[0].date?.toString() }
class="v-date-picker-month__days"
>
{ !props.hideWeekdays && adapter.getWeekdays().map(weekDay => (
{ !props.hideWeekdays && adapter.getWeekdays(props.firstDayOfWeek).map(weekDay => (
<div
class={[
'v-date-picker-month__day',
Expand Down
15 changes: 12 additions & 3 deletions packages/vuetify/src/composables/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface CalendarProps {
weekdays: number[]
year: number | string | undefined
weeksInMonth: 'dynamic' | 'static'
firstDayOfWeek: number | string | undefined

'onUpdate:modelValue': ((value: unknown[]) => void) | undefined
'onUpdate:month': ((value: number) => void) | undefined
Expand All @@ -47,6 +48,7 @@ export const makeCalendarProps = propsFactory({
type: String as PropType<'dynamic' | 'static'>,
default: 'dynamic',
},
firstDayOfWeek: [Number, String],
}, 'calendar')

export function useCalendar (props: CalendarProps) {
Expand Down Expand Up @@ -91,8 +93,14 @@ export function useCalendar (props: CalendarProps) {
v => adapter.getMonth(v)
)

const weekDays = computed(() => {
const firstDayOfWeek = Number(props.firstDayOfWeek ?? 0)

return props.weekdays.map(day => (day + firstDayOfWeek) % 7)
})

const weeksInMonth = computed(() => {
const weeks = adapter.getWeekArray(month.value)
const weeks = adapter.getWeekArray(month.value, props.firstDayOfWeek)

const days = weeks.flat()

Expand All @@ -118,7 +126,7 @@ export function useCalendar (props: CalendarProps) {

function genDays (days: unknown[], today: unknown) {
return days.filter(date => {
return props.weekdays.includes(adapter.toJsDate(date).getDay())
return weekDays.value.includes(adapter.toJsDate(date).getDay())
}).map((date, index) => {
const isoDate = adapter.toISO(date)
const isAdjacent = !adapter.isSameMonth(date, month.value)
Expand Down Expand Up @@ -148,7 +156,7 @@ export function useCalendar (props: CalendarProps) {
}

const daysInWeek = computed(() => {
const lastDay = adapter.startOfWeek(displayValue.value)
const lastDay = adapter.startOfWeek(displayValue.value, props.firstDayOfWeek)
const week = []
for (let day = 0; day <= 6; day++) {
week.push(adapter.addDays(lastDay, day))
Expand Down Expand Up @@ -198,6 +206,7 @@ export function useCalendar (props: CalendarProps) {
genDays,
model,
weeksInMonth,
weekDays,
weekNumbers,
}
}
6 changes: 3 additions & 3 deletions packages/vuetify/src/composables/date/DateAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface DateAdapter<T = unknown> {

startOfDay (date: T): T
endOfDay (date: T): T
startOfWeek (date: T): T
startOfWeek (date: T, firstDayOfWeek?: number | string): T
endOfWeek (date: T): T
startOfMonth (date: T): T
endOfMonth (date: T): T
Expand Down Expand Up @@ -35,8 +35,8 @@ export interface DateAdapter<T = unknown> {
getYear (date: T): number
setYear (date: T, year: number): T
getDiff (date: T, comparing: T | string, unit?: string): number
getWeekArray (date: T): T[][]
getWeekdays (): string[]
getWeekArray (date: T, firstDayOfWeek?: number | string): T[][]
getWeekdays (firstDayOfWeek?: number | string): string[]
getMonth (date: T): number
setMonth (date: T, month: number): T
getDate (date: T): number
Expand Down
29 changes: 16 additions & 13 deletions packages/vuetify/src/composables/date/adapters/vuetify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,14 @@ const firstDay: Record<string, number> = {
ZW: 0,
}

function getWeekArray (date: Date, locale: string) {
function getWeekArray (date: Date, locale: string, firstDayOfWeek?: number) {
const weeks = []
let currentWeek = []
const firstDayOfMonth = startOfMonth(date)
const lastDayOfMonth = endOfMonth(date)
const firstDayWeekIndex = (firstDayOfMonth.getDay() - firstDay[locale.slice(-2).toUpperCase()] + 7) % 7
const lastDayWeekIndex = (lastDayOfMonth.getDay() - firstDay[locale.slice(-2).toUpperCase()] + 7) % 7
const first = firstDayOfWeek ?? firstDay[locale.slice(-2).toUpperCase()] ?? 0
const firstDayWeekIndex = (firstDayOfMonth.getDay() - first + 7) % 7
const lastDayWeekIndex = (lastDayOfMonth.getDay() - first + 7) % 7

for (let i = 0; i < firstDayWeekIndex; i++) {
const adjacentDay = new Date(firstDayOfMonth)
Expand Down Expand Up @@ -200,9 +201,11 @@ function getWeekArray (date: Date, locale: string) {
return weeks
}

function startOfWeek (date: Date, locale: string) {
function startOfWeek (date: Date, locale: string, firstDayOfWeek?: number) {
const day = firstDayOfWeek ?? firstDay[locale.slice(-2).toUpperCase()] ?? 0

const d = new Date(date)
while (d.getDay() !== (firstDay[locale.slice(-2).toUpperCase()] ?? 0)) {
while (d.getDay() !== day) {
d.setDate(d.getDate() - 1)
}
return d
Expand Down Expand Up @@ -256,8 +259,8 @@ function date (value?: any): Date | null {

const sundayJanuarySecond2000 = new Date(2000, 0, 2)

function getWeekdays (locale: string) {
const daysFromSunday = firstDay[locale.slice(-2).toUpperCase()]
function getWeekdays (locale: string, firstDayOfWeek?: number) {
const daysFromSunday = firstDayOfWeek ?? firstDay[locale.slice(-2).toUpperCase()] ?? 0

return createRange(7).map(i => {
const weekday = new Date(sundayJanuarySecond2000)
Expand Down Expand Up @@ -601,12 +604,12 @@ export class VuetifyDateAdapter implements DateAdapter<Date> {
return addMonths(date, amount)
}

getWeekArray (date: Date) {
return getWeekArray(date, this.locale)
getWeekArray (date: Date, firstDayOfWeek?: number | string) {
return getWeekArray(date, this.locale, firstDayOfWeek ? Number(firstDayOfWeek) : undefined)
}

startOfWeek (date: Date): Date {
return startOfWeek(date, this.locale)
startOfWeek (date: Date, firstDayOfWeek?: number | string): Date {
return startOfWeek(date, this.locale, firstDayOfWeek ? Number(firstDayOfWeek) : undefined)
}

endOfWeek (date: Date): Date {
Expand Down Expand Up @@ -685,8 +688,8 @@ export class VuetifyDateAdapter implements DateAdapter<Date> {
return getDiff(date, comparing, unit)
}

getWeekdays () {
return getWeekdays(this.locale)
getWeekdays (firstDayOfWeek?: number | string) {
return getWeekdays(this.locale, firstDayOfWeek ? Number(firstDayOfWeek) : undefined)
}

getYear (date: Date) {
Expand Down
12 changes: 6 additions & 6 deletions packages/vuetify/src/labs/VCalendar/VCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const VCalendar = genericComponent<VCalendarSlots>()({
setup (props, { emit, slots }) {
const adapter = useDate()

const { daysInMonth, daysInWeek, genDays, model, displayValue, weekNumbers } = useCalendar(props as any)
const { daysInMonth, daysInWeek, genDays, model, displayValue, weekNumbers, weekDays } = useCalendar(props as any)

const dayNames = adapter.getWeekdays()

Expand Down Expand Up @@ -109,21 +109,21 @@ export const VCalendar = genericComponent<VCalendarSlots>()({
)}
</div>

<div class={['v-calendar__container', `days__${props.weekdays.length}`]}>
<div class={['v-calendar__container', `days__${weekDays.value.length}`]}>
{ props.viewMode === 'month' && !props.hideDayHeader && (
<div
class={
[
'v-calendar-weekly__head',
`days__${props.weekdays.length}`,
`days__${weekDays.value.length}`,
...(!props.hideWeekNumber ? ['v-calendar-weekly__head-weeknumbers'] : []),
]
}
key="calenderWeeklyHead"
>
{ !props.hideWeekNumber ? <div key="weekNumber0" class="v-calendar-weekly__head-weeknumber"></div> : '' }
{
props.weekdays.map(weekday => (
weekDays.value.map(weekday => (
<div class={ `v-calendar-weekly__head-weekday${!props.hideWeekNumber ? '-with-weeknumber' : ''}` }>
{ dayNames[weekday] }
</div>
Expand All @@ -138,12 +138,12 @@ export const VCalendar = genericComponent<VCalendarSlots>()({
class={
[
'v-calendar-month__days',
`days${!props.hideWeekNumber ? '-with-weeknumbers' : ''}__${props.weekdays.length}`,
`days${!props.hideWeekNumber ? '-with-weeknumbers' : ''}__${weekDays.value.length}`,
...(!props.hideWeekNumber ? ['v-calendar-month__weeknumbers'] : []),
]
}
>
{ chunkArray(daysInMonth.value, props.weekdays.length)
{ chunkArray(daysInMonth.value, weekDays.value.length)
.map((week, wi) => (
[
!props.hideWeekNumber ? <div class="v-calendar-month__weeknumber">{ weekNumbers.value[wi] }</div> : '',
Expand Down

0 comments on commit 77af0c6

Please sign in to comment.