diff --git a/packages/docs/components/Datepicker.md b/packages/docs/components/Datepicker.md index 46b004c9f..92be59017 100644 --- a/packages/docs/components/Datepicker.md +++ b/packages/docs/components/Datepicker.md @@ -45,7 +45,7 @@ title: Datepicker | closeOnClick | Close dropdown on click | boolean | - |
datepicker: {
closeOnClick: true
}
|
| dateCreator | Date creator function, default is `new Date()` | () => Date | - | datepicker: {
dateCreator: () => new Date()
}
|
| dateFormatter | Custom function to format a date into a string | (date: Date \| Date[]) => string | - | datepicker: {
dateFormatter: defaultFunction
}
|
-| dateParser | Custom function to parse a string into a date | (date: string) => Date | - | datepicker: {
dateParser: defaultFunction
}
|
+| dateParser | Custom function to parse a string into a date | (date: string) => Date \| Date[] | - | datepicker: {
dateParser: defaultFunction
}
|
| dayNames | Set custom day names, else use names based on locale | string[] | - | datepicker: {
dayNames: undefined
}
|
| disabled | Same as native disabled | boolean | - | false
|
| events | Events to display on picker | DatepickerEvent[] | - | |
diff --git a/packages/oruga/src/components/datepicker/Datepicker.vue b/packages/oruga/src/components/datepicker/Datepicker.vue
index d03ee830e..73912074a 100644
--- a/packages/oruga/src/components/datepicker/Datepicker.vue
+++ b/packages/oruga/src/components/datepicker/Datepicker.vue
@@ -116,9 +116,11 @@ const props = defineProps({
},
/** Custom function to parse a string into a date */
dateParser: {
- type: Function as PropType<(date: string) => Date>,
- default: (date: string, defaultFunction: (date: string) => Date) =>
- getOption("datepicker.dateParser", defaultFunction)(date),
+ type: Function as PropType<(date: string) => Date | Date[]>,
+ default: (
+ date: string,
+ defaultFunction: (date: string) => Date | Date[],
+ ) => getOption("datepicker.dateParser", defaultFunction)(date),
},
/** Date creator function, default is `new Date()` */
dateCreator: {
@@ -616,34 +618,30 @@ const isTypeMonth = computed(() => props.type === "month");
/**
* When v-model is changed:
* 1. Update internal value.
- * 2. If it's invalid, validate again.
*/
watch(
() => props.modelValue,
(value) => {
- // updateInternalState
- if (vmodel.value !== value) {
- const isArray = Array.isArray(value);
- const currentDate = isArray
- ? !value.length
- ? props.dateCreator()
- : value[value.length - 1]
- : !value
- ? props.dateCreator()
- : value;
- if (
- !isArray ||
- (isArray &&
- Array.isArray(vmodel.value) &&
- value.length > vmodel.value.length)
- ) {
- focusedDateData.value = {
- day: currentDate.getDate(),
- month: currentDate.getMonth(),
- year: currentDate.getFullYear(),
- };
- }
- }
+ const isArray = Array.isArray(value);
+ const currentDate = isArray
+ ? value.length
+ ? value[value.length - 1]
+ : props.dateCreator()
+ : value
+ ? value
+ : props.dateCreator();
+ if (
+ !isArray ||
+ (isArray &&
+ Array.isArray(vmodel.value) &&
+ value.length > vmodel.value.length)
+ )
+ // updateInternalState
+ focusedDateData.value = {
+ day: currentDate.getDate(),
+ month: currentDate.getMonth(),
+ year: currentDate.getFullYear(),
+ };
},
);
@@ -854,17 +852,14 @@ function formatNative(value: Date | Date[]): string {
function onChange(value: string): void {
const date = (props.dateParser as any)(value, defaultDateParser);
- if (
+ const isValid =
isDate(date) ||
(Array.isArray(date) &&
date.length === 2 &&
isDate(date[0]) &&
- isDate(date[1]))
- ) {
- vmodel.value = date;
- } else {
- vmodel.value = null;
- }
+ isDate(date[1]));
+
+ vmodel.value = isValid ? date : null;
}
/** Parse date from string */
diff --git a/packages/oruga/src/components/datepicker/useDatepickerMixins.ts b/packages/oruga/src/components/datepicker/useDatepickerMixins.ts
index 9095daa27..b94e59c8c 100644
--- a/packages/oruga/src/components/datepicker/useDatepickerMixins.ts
+++ b/packages/oruga/src/components/datepicker/useDatepickerMixins.ts
@@ -97,6 +97,7 @@ export function useDatepickerMixins(props: DatepickerProps) {
const defaultDateFormatter = (date: Date | Date[]): string => {
if (!date) return "";
const targetDates = Array.isArray(date) ? date : [date];
+ if (!targetDates.length) return "";
const dates = targetDates.map((date) => {
const d = new Date(
date.getFullYear(),
@@ -112,57 +113,63 @@ export function useDatepickerMixins(props: DatepickerProps) {
};
/** Parse a string into a date */
- const defaultDateParser = (date: string): Date => {
+ const defaultDateParser = (date: string): Date[] | Date => {
if (!date) return null;
- if (
- dtf.value.formatToParts &&
- typeof dtf.value.formatToParts === "function"
- ) {
- const formatRegex = (isTypeMonth.value ? dtfMonth.value : dtf.value)
- .formatToParts(sampleTime.value)
- .map((part) => {
- if (part.type === "literal") return part.value;
- return `((?!=<${part.type}>)\\d+)`;
- })
- .join("");
- const dateGroups = matchWithGroups(formatRegex, date);
-
- // We do a simple validation for the group.
- // If it is not valid, it will fallback to Date.parse below
+ const targetDates = !props.multiple ? [date] : date.split(", ");
+ const dates = targetDates.map((date) => {
if (
- dateGroups.year &&
- dateGroups.year.length === 4 &&
- dateGroups.month &&
- dateGroups.month <= 12
+ dtf.value.formatToParts &&
+ typeof dtf.value.formatToParts === "function"
) {
- if (isTypeMonth.value)
- return new Date(dateGroups.year, dateGroups.month - 1);
- else if (dateGroups.day && dateGroups.day <= 31) {
- return new Date(
- dateGroups.year,
- dateGroups.month - 1,
- dateGroups.day,
- 12,
- );
+ const formatRegex = (
+ isTypeMonth.value ? dtfMonth.value : dtf.value
+ )
+ .formatToParts(sampleTime.value)
+ .map((part) => {
+ if (part.type === "literal") return part.value;
+ return `((?!=<${part.type}>)\\d+)`;
+ })
+ .join("");
+ const dateGroups = matchWithGroups(formatRegex, date);
+
+ // We do a simple validation for the group.
+ // If it is not valid, it will fallback to Date.parse below
+ if (
+ dateGroups.year &&
+ dateGroups.year.length === 4 &&
+ dateGroups.month &&
+ dateGroups.month <= 12
+ ) {
+ if (isTypeMonth.value)
+ return new Date(dateGroups.year, dateGroups.month - 1);
+ else if (dateGroups.day && dateGroups.day <= 31) {
+ return new Date(
+ dateGroups.year,
+ dateGroups.month - 1,
+ dateGroups.day,
+ 12,
+ );
+ }
}
}
- }
- // Fallback if formatToParts is not supported or if we were not able to parse a valid date
- if (!isTypeMonth.value) return new Date(Date.parse(date));
- const s = date.split("/");
- const year = s[0].length === 4 ? s[0] : s[1];
- const month = s[0].length === 2 ? s[0] : s[1];
- if (year && month) {
- return new Date(
- parseInt(year, 10),
- parseInt(month, 10) - 1,
- 1,
- 0,
- 0,
- 0,
- 0,
- );
- }
+ // Fallback if formatToParts is not supported or if we were not able to parse a valid date
+ if (!isTypeMonth.value) return new Date(Date.parse(date));
+ const s = date.split("/");
+ const year = s[0].length === 4 ? s[0] : s[1];
+ const month = s[0].length === 2 ? s[0] : s[1];
+ if (year && month) {
+ return new Date(
+ parseInt(year, 10),
+ parseInt(month, 10) - 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ );
+ }
+ });
+ return props.multiple ? dates : dates[0];
};
return { isDateSelectable, defaultDateParser, defaultDateFormatter };
diff --git a/packages/oruga/src/components/datetimepicker/examples/base.vue b/packages/oruga/src/components/datetimepicker/examples/base.vue
index 704f93bec..30b89c8bf 100644
--- a/packages/oruga/src/components/datetimepicker/examples/base.vue
+++ b/packages/oruga/src/components/datetimepicker/examples/base.vue
@@ -47,7 +47,6 @@ const locale = ref(); // Browser locale