Skip to content

Commit 5933508

Browse files
feat(DateRangePicker/RangeCalendar): add isDateHighlightable property (#1816)
* feat: implement isDateHighlightable * docs: add docs * fix: move isDateHighlightable from useCalendar.ts to useRangeCalendar.ts --------- Co-authored-by: Jan Sahrhage <sahrhage@be-on.de>
1 parent 7d96922 commit 5933508

File tree

7 files changed

+55
-7
lines changed

7 files changed

+55
-7
lines changed

docs/content/meta/DateRangePickerRoot.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@
9797
'type': 'Matcher',
9898
'required': false
9999
},
100+
{
101+
'name': 'isDateHighlightable',
102+
'description': '<p>A function that returns whether or not a date is highlightable</p>\n',
103+
'type': 'Matcher',
104+
'required': false
105+
},
100106
{
101107
'name': 'locale',
102108
'description': '<p>The locale to use for formatting dates</p>\n',
@@ -243,5 +249,10 @@
243249
'name': 'isDateUnavailable',
244250
'description': '<p>A function that returns whether or not a date is unavailable</p>\n',
245251
'type': 'Matcher'
246-
}
252+
},
253+
{
254+
'name': 'isDateHighlightable',
255+
'description': '<p>A function that returns whether or not a date is highlightable</p>\n',
256+
'type': 'Matcher'
257+
},
247258
]" />

docs/content/meta/RangeCalendarRoot.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@
7979
'type': 'Matcher',
8080
'required': false
8181
},
82+
{
83+
'name': 'isDateHighlightable',
84+
'description': '<p>A function that returns whether or not a date is highlightable</p>\n',
85+
'type': 'Matcher',
86+
'required': false
87+
},
8288
{
8389
'name': 'locale',
8490
'description': '<p>The locale to use for formatting dates</p>\n',
@@ -231,5 +237,10 @@
231237
'name': 'isDateUnavailable',
232238
'description': '<p>A function that returns whether or not a date is unavailable</p>\n',
233239
'type': 'Matcher'
234-
}
240+
},
241+
{
242+
'name': 'isDateHighlightable',
243+
'description': '<p>A function that returns whether or not a date is highlightable</p>\n',
244+
'type': 'Matcher'
245+
},
235246
]" />

packages/core/src/DateRangePicker/DateRangePickerCalendar.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const rootContext = injectDateRangePickerRootContext()
1515
allowNonContiguousRanges: rootContext.allowNonContiguousRanges.value,
1616
isDateDisabled: rootContext.isDateDisabled,
1717
isDateUnavailable: rootContext.isDateUnavailable,
18+
isDateHighlightable: rootContext.isDateHighlightable,
1819
locale: rootContext.locale.value,
1920
disabled: rootContext.disabled.value,
2021
pagedNavigation: rootContext.pagedNavigation.value,

packages/core/src/DateRangePicker/DateRangePickerRoot.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type DateRangePickerRootContext = {
3232
readonly: Ref<boolean>
3333
isDateDisabled?: Matcher
3434
isDateUnavailable?: Matcher
35+
isDateHighlightable?: Matcher
3536
defaultOpen: Ref<boolean>
3637
open: Ref<boolean>
3738
modal: Ref<boolean>
@@ -42,7 +43,7 @@ type DateRangePickerRootContext = {
4243
allowNonContiguousRanges: Ref<boolean>
4344
}
4445
45-
export type DateRangePickerRootProps = DateRangeFieldRootProps & PopoverRootProps & Pick<RangeCalendarRootProps, 'isDateDisabled' | 'pagedNavigation' | 'weekStartsOn' | 'weekdayFormat' | 'fixedWeeks' | 'numberOfMonths' | 'preventDeselect' | 'isDateUnavailable' | 'allowNonContiguousRanges'>
46+
export type DateRangePickerRootProps = DateRangeFieldRootProps & PopoverRootProps & Pick<RangeCalendarRootProps, 'isDateDisabled' | 'pagedNavigation' | 'weekStartsOn' | 'weekdayFormat' | 'fixedWeeks' | 'numberOfMonths' | 'preventDeselect' | 'isDateUnavailable' | 'isDateHighlightable' | 'allowNonContiguousRanges'>
4647
4748
export type DateRangePickerRootEmits = {
4849
/** Event handler called whenever the model value changes */
@@ -82,6 +83,7 @@ const props = withDefaults(defineProps<DateRangePickerRootProps>(), {
8283
locale: 'en',
8384
isDateDisabled: undefined,
8485
isDateUnavailable: undefined,
86+
isDateHighlightable: undefined,
8587
allowNonContiguousRanges: false,
8688
})
8789
const emits = defineEmits<DateRangePickerRootEmits & PopoverRootEmits>()
@@ -97,6 +99,7 @@ const {
9799
preventDeselect,
98100
isDateDisabled: propsIsDateDisabled,
99101
isDateUnavailable: propsIsDateUnavailable,
102+
isDateHighlightable: propsIsDateHighlightable,
100103
defaultOpen,
101104
modal,
102105
id,
@@ -147,6 +150,7 @@ provideDateRangePickerRootContext({
147150
allowNonContiguousRanges,
148151
isDateUnavailable: propsIsDateUnavailable.value,
149152
isDateDisabled: propsIsDateDisabled.value,
153+
isDateHighlightable: propsIsDateHighlightable.value,
150154
locale,
151155
disabled,
152156
pagedNavigation,

packages/core/src/RangeCalendar/RangeCalendarRoot.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type RangeCalendarRootContext = {
3535
isInvalid: Ref<boolean>
3636
isDateDisabled: Matcher
3737
isDateUnavailable?: Matcher
38+
isDateHighlightable?: Matcher
3839
isOutsideVisibleView: (date: DateValue) => boolean
3940
highlightedRange: Ref<{ start: DateValue, end: DateValue } | null>
4041
focusedValue: Ref<DateValue | undefined>
@@ -93,6 +94,8 @@ export interface RangeCalendarRootProps extends PrimitiveProps {
9394
isDateDisabled?: Matcher
9495
/** A function that returns whether or not a date is unavailable */
9596
isDateUnavailable?: Matcher
97+
/** A function that returns whether or not a date is hightable */
98+
isDateHighlightable?: Matcher
9699
/** The reading direction of the calendar when applicable. <br> If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. */
97100
dir?: Direction
98101
/** A function that returns the next page of the calendar. It receives the current placeholder as an argument inside the component. */
@@ -134,6 +137,7 @@ const props = withDefaults(defineProps<RangeCalendarRootProps>(), {
134137
placeholder: undefined,
135138
isDateDisabled: undefined,
136139
isDateUnavailable: undefined,
140+
isDateHighlightable: undefined,
137141
allowNonContiguousRanges: false,
138142
})
139143
const emits = defineEmits<RangeCalendarRootEmits>()
@@ -168,6 +172,7 @@ const {
168172
numberOfMonths,
169173
preventDeselect,
170174
isDateUnavailable: propsIsDateUnavailable,
175+
isDateHighlightable: propsIsDateHighlightable,
171176
isDateDisabled: propsIsDateDisabled,
172177
calendarLabel,
173178
maxValue,
@@ -247,6 +252,7 @@ const {
247252
const {
248253
isInvalid,
249254
isSelected,
255+
isDateHighlightable,
250256
highlightedRange,
251257
isSelectionStart,
252258
isSelectionEnd,
@@ -257,6 +263,7 @@ const {
257263
end: endValue,
258264
isDateDisabled,
259265
isDateUnavailable,
266+
isDateHighlightable: propsIsDateHighlightable.value,
260267
focusedValue,
261268
allowNonContiguousRanges,
262269
})
@@ -323,6 +330,7 @@ useEventListener('keydown', (ev) => {
323330
324331
provideRangeCalendarRootContext({
325332
isDateUnavailable,
333+
isDateHighlightable,
326334
startValue,
327335
endValue,
328336
formatter,

packages/core/src/RangeCalendar/useRangeCalendar.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type UseRangeCalendarProps = {
1111
end: Ref<DateValue | undefined>
1212
isDateDisabled: Matcher
1313
isDateUnavailable: Matcher
14+
isDateHighlightable?: Matcher
1415
focusedValue: Ref<DateValue | undefined>
1516
allowNonContiguousRanges: Ref<boolean>
1617
}
@@ -65,6 +66,12 @@ export function useRangeCalendarState(props: UseRangeCalendarProps) {
6566
return false
6667
}
6768

69+
const isDateHighlightable = (date: DateValue) => {
70+
if (props.isDateHighlightable?.(date))
71+
return true
72+
return false
73+
}
74+
6875
const highlightedRange = computed(() => {
6976
if (props.start.value && props.end.value)
7077
return null
@@ -82,7 +89,7 @@ export function useRangeCalendarState(props: UseRangeCalendarProps) {
8289
}
8390
}
8491

85-
const isValid = props.allowNonContiguousRanges.value || areAllDaysBetweenValid(start, end, props.isDateUnavailable, props.isDateDisabled)
92+
const isValid = areAllDaysBetweenValid(start, end, props.allowNonContiguousRanges.value ? () => false : props.isDateUnavailable, props.isDateDisabled, props.isDateHighlightable)
8693
if (isValid) {
8794
return {
8895
start,
@@ -107,6 +114,7 @@ export function useRangeCalendarState(props: UseRangeCalendarProps) {
107114
return {
108115
isInvalid,
109116
isSelected,
117+
isDateHighlightable,
110118
highlightedRange,
111119
isSelectionStart,
112120
isSelectionEnd,

packages/core/src/date/comparators.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,19 +175,24 @@ export function areAllDaysBetweenValid(
175175
end: DateValue,
176176
isUnavailable: Matcher | undefined,
177177
isDisabled: Matcher | undefined,
178+
isHighlightable?: Matcher | undefined,
178179
) {
179-
if (isUnavailable === undefined && isDisabled === undefined)
180+
if (isUnavailable === undefined && isDisabled === undefined && isHighlightable === undefined)
180181
return true
181182

182183
let dCurrent = start.add({ days: 1 })
183-
if (isDisabled?.(dCurrent) || isUnavailable?.(dCurrent))
184+
if ((isDisabled?.(dCurrent) || isUnavailable?.(dCurrent))
185+
&& !isHighlightable?.(dCurrent)) {
184186
return false
187+
}
185188

186189
const dEnd = end
187190
while (dCurrent.compare(dEnd) < 0) {
188191
dCurrent = dCurrent.add({ days: 1 })
189-
if (isDisabled?.(dCurrent) || isUnavailable?.(dCurrent))
192+
if ((isDisabled?.(dCurrent) || isUnavailable?.(dCurrent))
193+
&& !isHighlightable?.(dCurrent)) {
190194
return false
195+
}
191196
}
192197
return true
193198
}

0 commit comments

Comments
 (0)