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

fix(calendar): add missing first-day-of-week property support #20096

Merged
merged 1 commit into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix(calendar): add missing first-day-of-week property support
  • Loading branch information
johnleider committed Jul 3, 2024
commit 6b1e31b2d042f93a0cb5225d4530eded3e8294ec
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
Loading