From 908ea8ca5d3bd6f2f35a40ac81b3ca738b05e4f9 Mon Sep 17 00:00:00 2001 From: zernonia <59365435+zernonia@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:29:12 +0800 Subject: [PATCH] fix(DatePicker): `ar-SA` locale causing error (#1476) * fix: add fallback, era sgment attributes * feat: support locale awareness for calendar when no default value or placeholder given * chore: cleanup --- .../radix-vue/src/Calendar/CalendarRoot.vue | 1 + .../radix-vue/src/DateField/DateFieldRoot.vue | 1 + .../radix-vue/src/DateField/useDateField.ts | 25 +++++++++++++++++-- .../src/DatePicker/DatePickerRoot.vue | 1 + .../story/DatePickerDefault.story.vue | 2 +- .../src/DateRangeField/DateRangeFieldRoot.vue | 1 + .../DateRangePicker/DateRangePickerRoot.vue | 1 + .../src/RangeCalendar/RangeCalendarRoot.vue | 1 + .../radix-vue/src/shared/date/comparators.ts | 12 ++++++--- 9 files changed, 38 insertions(+), 7 deletions(-) diff --git a/packages/radix-vue/src/Calendar/CalendarRoot.vue b/packages/radix-vue/src/Calendar/CalendarRoot.vue index fb298137b..afc1d4878 100644 --- a/packages/radix-vue/src/Calendar/CalendarRoot.vue +++ b/packages/radix-vue/src/Calendar/CalendarRoot.vue @@ -190,6 +190,7 @@ const modelValue = useVModel(props, 'modelValue', emits, { const defaultDate = getDefaultDate({ defaultPlaceholder: props.placeholder, defaultValue: modelValue.value, + locale: props.locale, }) const placeholder = useVModel(props, 'placeholder', emits, { diff --git a/packages/radix-vue/src/DateField/DateFieldRoot.vue b/packages/radix-vue/src/DateField/DateFieldRoot.vue index 514dbbe7b..6f0869607 100644 --- a/packages/radix-vue/src/DateField/DateFieldRoot.vue +++ b/packages/radix-vue/src/DateField/DateFieldRoot.vue @@ -130,6 +130,7 @@ const defaultDate = getDefaultDate({ defaultPlaceholder: props.placeholder, granularity: granularity.value, defaultValue: modelValue.value, + locale: props.locale, }) const placeholder = useVModel(props, 'placeholder', emits, { diff --git a/packages/radix-vue/src/DateField/useDateField.ts b/packages/radix-vue/src/DateField/useDateField.ts index fd9db15ab..6600a527d 100644 --- a/packages/radix-vue/src/DateField/useDateField.ts +++ b/packages/radix-vue/src/DateField/useDateField.ts @@ -215,6 +215,24 @@ function timeZoneSegmentAttrs(props: SegmentAttrProps) { } } +function eraSegmentAttrs(props: SegmentAttrProps) { + const { segmentValues, placeholder } = props + + const valueMin = 0 + const valueMax = 0 + const valueNow = 0 + const valueText = 'era' in segmentValues ? segmentValues.era : placeholder.era + + return { + ...commonSegmentAttrs(props), + 'aria-label': 'era', + 'aria-valuemin': valueMin, + 'aria-valuemax': valueMax, + 'aria-valuenow': valueNow, + 'aria-valuetext': valueText, + } +} + export const segmentBuilders = { day: { attrs: daySegmentAttrs, @@ -243,6 +261,9 @@ export const segmentBuilders = { timeZoneName: { attrs: timeZoneSegmentAttrs, }, + era: { + attrs: eraSegmentAttrs, + }, } export type UseDateFieldProps = { @@ -569,13 +590,13 @@ export function useDateField(props: UseDateFieldProps) { return { value: int, moveToNext } } - const attributes = computed(() => segmentBuilders[props.part].attrs({ + const attributes = computed(() => segmentBuilders[props.part]?.attrs({ disabled: props.disabled.value, placeholder: props.placeholder.value, hourCycle: props.hourCycle, segmentValues: props.segmentValues.value, formatter: props.formatter, - })) + }) ?? {}) // TODO: look into abstracting segment keydown functions since they have the same structure (checks -> arrow_up, arrow_down update -> number string update -> move to next -> backspace update) function handleDaySegmentKeydown(e: KeyboardEvent) { diff --git a/packages/radix-vue/src/DatePicker/DatePickerRoot.vue b/packages/radix-vue/src/DatePicker/DatePickerRoot.vue index a0eeb8c41..7df65e6f6 100644 --- a/packages/radix-vue/src/DatePicker/DatePickerRoot.vue +++ b/packages/radix-vue/src/DatePicker/DatePickerRoot.vue @@ -116,6 +116,7 @@ const defaultDate = computed(() => getDefaultDate({ defaultPlaceholder: props.placeholder, granularity: props.granularity, defaultValue: modelValue.value, + locale: props.locale, })) const placeholder = useVModel(props, 'placeholder', emits, { diff --git a/packages/radix-vue/src/DatePicker/story/DatePickerDefault.story.vue b/packages/radix-vue/src/DatePicker/story/DatePickerDefault.story.vue index baa6f7478..38dd83b97 100644 --- a/packages/radix-vue/src/DatePicker/story/DatePickerDefault.story.vue +++ b/packages/radix-vue/src/DatePicker/story/DatePickerDefault.story.vue @@ -34,7 +34,7 @@ import { Label } from '@/Label' diff --git a/packages/radix-vue/src/shared/date/comparators.ts b/packages/radix-vue/src/shared/date/comparators.ts index 0253bccbe..136886c52 100644 --- a/packages/radix-vue/src/shared/date/comparators.ts +++ b/packages/radix-vue/src/shared/date/comparators.ts @@ -2,7 +2,7 @@ * Implementation ported from https://github.com/melt-ui/melt-ui/blob/develop/src/lib/internal/helpers/date/utils.ts */ -import { CalendarDate, CalendarDateTime, type DateValue } from '@internationalized/date' +import { CalendarDate, CalendarDateTime, DateFormatter, type DateValue, createCalendar, toCalendar } from '@internationalized/date' export type Granularity = 'day' | 'hour' | 'minute' | 'second' @@ -10,6 +10,7 @@ type GetDefaultDateProps = { defaultValue?: DateValue | DateValue[] | undefined defaultPlaceholder?: DateValue | undefined granularity?: Granularity + locale?: string } /** @@ -23,7 +24,7 @@ type GetDefaultDateProps = { * */ export function getDefaultDate(props: GetDefaultDateProps): DateValue { - const { defaultValue, defaultPlaceholder, granularity = 'day' } = props + const { defaultValue, defaultPlaceholder, granularity = 'day', locale = 'en' } = props if (Array.isArray(defaultValue) && defaultValue.length) return defaultValue.at(-1)!.copy() @@ -40,8 +41,11 @@ export function getDefaultDate(props: GetDefaultDateProps): DateValue { const day = date.getDate() const calendarDateTimeGranularities = ['hour', 'minute', 'second'] + const defaultFormatter = new DateFormatter(locale) + const calendar = createCalendar(defaultFormatter.resolvedOptions().calendar) + if (calendarDateTimeGranularities.includes(granularity ?? 'day')) - return new CalendarDateTime(year, month, day, 0, 0, 0) + return toCalendar(new CalendarDateTime(year, month, day, 0, 0, 0), calendar) - return new CalendarDate(year, month, day) + return toCalendar(new CalendarDate(year, month, day), calendar) }