@@ -163,6 +163,66 @@ export default {
163163}
164164</script>
165165```
166+
167+ ### Restricting to a specific time range
168+
169+ You can optionally restring the selectable time range, for example from 08:00 on Monday to 20:00 on Sunday.
170+
171+ ```vue
172+ <template>
173+ <div>
174+ <NcDateTimePicker
175+ v-model="selected"
176+ type="datetime"
177+ :min="min"
178+ :max="max" />
179+ <p>Selected: {{ selected }}</p>
180+ </div>
181+ </template>
182+ <script>
183+ export default {
184+ data() {
185+ const now = new Date()
186+ const day = now.getDay()
187+ const daysSinceMonday = (day + 6) % 7
188+
189+ const startOfWeek = new Date(now)
190+ startOfWeek.setDate(now.getDate() - daysSinceMonday)
191+ startOfWeek.setHours(8, 0, 0, 0)
192+
193+ const endOfWeek = new Date(startOfWeek)
194+ endOfWeek.setDate(startOfWeek.getDate() + 6)
195+ endOfWeek.setHours(20, 0, 0, 0)
196+
197+ return {
198+ selected: null,
199+ min: startOfWeek,
200+ max: endOfWeek,
201+ }
202+ },
203+ }
204+ </script>
205+ ```
206+
207+ ### Inline calendar
208+
209+ Renders the calendar inline (without the text input) inside your parent component.
210+
211+ ```vue
212+ <template>
213+ <div>
214+ <NcDateTimePicker v-model="date" inline />
215+ <p>Selected: {{ date }}</p>
216+ </div>
217+ </template>
218+ <script>
219+ export default {
220+ data() {
221+ return { date: new Date() }
222+ },
223+ }
224+ </script>
225+ ```
166226</docs >
167227
168228<script setup lang="ts">
@@ -259,6 +319,16 @@ const props = withDefaults(defineProps<{
259319 */
260320 locale? : string
261321
322+ /**
323+ * The maximum date that can be selected.
324+ */
325+ max? : Date
326+
327+ /**
328+ * The minimum date that can be selected.
329+ */
330+ min? : Date
331+
262332 /**
263333 * Default increment step for minutes in the time picker.
264334 *
@@ -306,17 +376,27 @@ const props = withDefaults(defineProps<{
306376 * @default ' date'
307377 */
308378 type? : ' date' | ' datetime' | ' time' | ' week' | ' month' | ' year' | ' date-range' | ' time-range' | ' datetime-range'
379+
380+ /**
381+ * Render the calendar inline (no input field).
382+ *
383+ * @default false
384+ */
385+ inline? : boolean
309386}>(), {
310387 ariaLabel: t (' Datepicker input' ),
311388 ariaLabelMenu: t (' Datepicker menu' ),
312389 format: undefined ,
313390 locale: getCanonicalLocale (),
391+ max: undefined ,
392+ min: undefined ,
314393 minuteStep: 10 ,
315394 timezoneId: ' UTC' ,
316395 modelValue: null ,
317396 // set by fallbackPlaceholder
318397 placeholder: undefined ,
319398 type: ' date' ,
399+ inline: false ,
320400})
321401
322402const emit = defineEmits <{
@@ -327,6 +407,10 @@ const emit = defineEmits<{
327407 */
328408 ' update:modelValue' : [Date | [Date , Date ] | null ]
329409 ' update:timezoneId' : [string ]
410+ /**
411+ * Input blur
412+ */
413+ blur: []
330414}>()
331415
332416const targetElement = useTemplateRef (' target' )
@@ -463,6 +547,10 @@ const pickerType = computed(() => ({
463547 : undefined ,
464548}))
465549
550+ // Convert min/max Date into VueDatePicker's time object shape
551+ const minTime = computed (() => props .min && { hours: props .min .getHours (), minutes: props .min .getMinutes (), seconds: props .min .getSeconds () })
552+ const maxTime = computed (() => props .max && { hours: props .max .getHours (), minutes: props .max .getMinutes (), seconds: props .max .getSeconds () })
553+
466554/**
467555 * Called on model value update of the library.
468556 *
@@ -587,6 +675,20 @@ function selectDate() {
587675function cancelSelection() {
588676 pickerInstance .value ! .closeMenu ()
589677}
678+
679+ /**
680+ * Check if two dates are on the same day.
681+ *
682+ * @param a
683+ * @param b
684+ */
685+ function sameDay(a : Date , b : Date ): boolean {
686+ return (
687+ a .getFullYear () === b .getFullYear ()
688+ && a .getMonth () === b .getMonth ()
689+ && a .getDate () === b .getDate ()
690+ )
691+ }
590692 </script >
591693
592694<template >
@@ -603,18 +705,24 @@ function cancelSelection() {
603705 :placeholder =" placeholder ?? placeholderFallback"
604706 :format =" realFormat"
605707 :locale
708+ :min-date =" min"
709+ :max-date =" max"
710+ :min-time =" min ? sameDay(min, value) ? minTime : undefined : undefined"
711+ :max-time =" max ? sameDay(max, value) ? maxTime : undefined : undefined"
606712 :minutes-increment =" minuteStep"
607713 :model-value =" value"
608714 :now-button-label =" t('Now')"
609715 :select-text =" t('Pick')"
610716 six-weeks =" fair"
717+ :inline
611718 :teleport =" appendToBody ? (targetElement || undefined) : false"
612719 text-input
613720 :week-num-name
614721 :week-numbers =" showWeekNumber ? { type: 'iso' } : undefined"
615722 :week-start
616723 v-bind =" pickerType"
617- @update:model-value =" onUpdateModelValue" >
724+ @update:model-value =" onUpdateModelValue"
725+ @blur =" emit('blur')" >
618726 <template #action-buttons >
619727 <NcButton size =" small" variant =" tertiary" @click =" cancelSelection" >
620728 {{ t('Cancel') }}
0 commit comments