Teren-app/resources/js/Components/DatePickerField.vue
2025-10-05 19:45:49 +02:00

107 lines
3.4 KiB
Vue

<script setup>
import InputLabel from "./InputLabel.vue";
import InputError from "./InputError.vue";
import { computed } from "vue";
/*
DatePickerField (v-calendar)
- A thin wrapper around <VDatePicker> with a label and error support.
- Uses v-calendar which handles popovers/teleport well inside modals.
API: kept compatible with previous usage where possible.
Props:
- modelValue: Date | string | number | null
- id: string
- label: string
- format: string (default 'dd.MM.yyyy')
- enableTimePicker: boolean (default false)
- inline: boolean (default false) // When true, keeps the popover visible
- placeholder: string
- error: string | string[]
Note: Props like teleportTarget/autoPosition/menuClassName/fixed/closeOn... were for the old picker
and are accepted for compatibility but are not used by v-calendar.
*/
const props = defineProps({
modelValue: { type: [Date, String, Number, null], default: null },
id: { type: String, default: undefined },
label: { type: String, default: undefined },
format: { type: String, default: "dd.MM.yyyy" },
enableTimePicker: { type: Boolean, default: false },
inline: { type: Boolean, default: false },
// legacy/unused in v-calendar (kept to prevent breaking callers)
autoApply: { type: Boolean, default: false },
teleportTarget: { type: [Boolean, String], default: "body" },
autoPosition: { type: Boolean, default: true },
menuClassName: { type: String, default: "dp-over-modal" },
fixed: { type: Boolean, default: true },
closeOnAutoApply: { type: Boolean, default: true },
closeOnScroll: { type: Boolean, default: true },
placeholder: { type: String, default: "" },
error: { type: [String, Array], default: undefined },
});
const emit = defineEmits(["update:modelValue", "change"]);
const valueProxy = computed({
get: () => props.modelValue,
set: (val) => {
emit("update:modelValue", val);
emit("change", val);
},
});
// Convert common date mask from lowercase tokens to v-calendar tokens
const inputMask = computed(() => {
let m = props.format || "dd.MM.yyyy";
return (
m.replace(/yyyy/g, "YYYY").replace(/dd/g, "DD").replace(/MM/g, "MM") +
(props.enableTimePicker ? " HH:mm" : "")
);
});
const popoverCfg = computed(() => ({
visibility: props.inline ? "visible" : "click",
placement: "bottom-start",
}));
</script>
<template>
<div class="col-span-6 sm:col-span-4">
<InputLabel v-if="label" :for="id" :value="label" />
<!-- VCalendar DatePicker with custom input to keep Tailwind styling -->
<VDatePicker
v-model="valueProxy"
:mode="enableTimePicker ? 'dateTime' : 'date'"
:masks="{ input: inputMask }"
:popover="popoverCfg"
:is24hr="true"
>
<template #default="{ inputValue, inputEvents }">
<input
:id="id"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
:placeholder="placeholder"
:value="inputValue"
autocomplete="off"
v-on="inputEvents"
/>
</template>
</VDatePicker>
<template v-if="error">
<InputError
v-if="Array.isArray(error)"
v-for="(e, idx) in error"
:key="idx"
:message="e"
/>
<InputError v-else :message="error" />
</template>
</div>
</template>
<style>
/* Ensure the date picker menu overlays modals/dialogs */
</style>