Skip to content

Commit

Permalink
fix(DatePicker): ar-SA locale causing error (#1476)
Browse files Browse the repository at this point in the history
* fix: add fallback, era sgment attributes

* feat: support locale awareness for calendar when no default value or placeholder given

* chore: cleanup
  • Loading branch information
zernonia authored Dec 5, 2024
1 parent a2d2b1a commit 908ea8c
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/radix-vue/src/Calendar/CalendarRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down
1 change: 1 addition & 0 deletions packages/radix-vue/src/DateField/DateFieldRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down
25 changes: 23 additions & 2 deletions packages/radix-vue/src/DateField/useDateField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -243,6 +261,9 @@ export const segmentBuilders = {
timeZoneName: {
attrs: timeZoneSegmentAttrs,
},
era: {
attrs: eraSegmentAttrs,
},
}

export type UseDateFieldProps = {
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions packages/radix-vue/src/DatePicker/DatePickerRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { Label } from '@/Label'
<DatePickerRoot
id="date-field"
:is-date-unavailable="date => date.day === 19"
granularity="second"
locale="ar-SA"
>
<DatePickerField
v-slot="{ segments }"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ const defaultDate = getDefaultDate({
defaultPlaceholder: props.placeholder,
granularity: props.granularity,
defaultValue: modelValue.value.start,
locale: props.locale,
})
const placeholder = useVModel(props, 'placeholder', emits, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const defaultDate = getDefaultDate({
defaultPlaceholder: props.placeholder,
granularity: props.granularity,
defaultValue: modelValue.value.start,
locale: props.locale,
})
const placeholder = useVModel(props, 'placeholder', emits, {
Expand Down
1 change: 1 addition & 0 deletions packages/radix-vue/src/RangeCalendar/RangeCalendarRoot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ const modelValue = useVModel(props, 'modelValue', emits, {
const defaultDate = getDefaultDate({
defaultPlaceholder: props.placeholder,
defaultValue: modelValue.value.start,
locale: props.locale,
})
const startValue = ref(modelValue.value.start) as Ref<DateValue | undefined>
Expand Down
12 changes: 8 additions & 4 deletions packages/radix-vue/src/shared/date/comparators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
* 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'

type GetDefaultDateProps = {
defaultValue?: DateValue | DateValue[] | undefined
defaultPlaceholder?: DateValue | undefined
granularity?: Granularity
locale?: string
}

/**
Expand All @@ -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()
Expand All @@ -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)
}

0 comments on commit 908ea8c

Please sign in to comment.