vuetifyjs / vuetify

🐉 Vue Component Framework
https://vuetifyjs.com
MIT License
39.86k stars 6.97k forks source link

[Feature Request] v-date-picker (Date range) #18725

Closed Ploypln closed 11 months ago

Ploypln commented 11 months ago

Problem to solve

I can't find any date range functions.

Proposed solution

I want to use a date range selection but can't find any date range functions.

johnleider commented 11 months ago

This is already planned.

cvaroregidor commented 11 months ago

Any idea of when it can be released?

Saveriu commented 9 months ago

Hello, I have a fix for that, here a piece of code to have a range:


<template>
  <div>
    <v-menu
      v-model="menu"
      :close-on-content-click="false"
      close-on-click
      transition="scale-transition"
      offset-y
    >
      <template v-slot:activator="{ props }">
        <v-btn v-bind="props" variant="flat" :text="dateRangeText">
          <template #append>
            <v-icon color="white"> mdi-calendar-blank </v-icon>
          </template>
        </v-btn>
      </template>

      <v-date-picker
        hide-header
        v-model="dates"
        class="datePicker mt-4"
        show-adjacent-months
        show-current
        scrollable
        rounded
        elevation="5"
        :max="new Date()"
      >
        <template #actions>
          <v-btn color="primary" variant="text" @click="cancel" :text="$t('cancel')" />
          <v-btn color="primary" variant="text" @click="save" :text="$t('ok')" />
        </template>
      </v-date-picker>
    </v-menu>
  </div>
</template>
<style lang="scss">
.datePicker {

  border-radius: 20px !important;

  .v-date-picker-month__day--selected {
    background-color: #384b4e;
  }

  .v-date-picker-month__day--selected .v-btn,
  .v-date-picker-month__day .v-btn {
    background-color: transparent !important;
    color: white !important;
  }

  :nth-child(1 of .v-date-picker-month__day--selected) {
    border-radius: 50% 0 0 50%;
    .v-btn {
      background-color: #359c97 !important;
    }
  }

  :nth-last-child(1 of .v-date-picker-month__day--selected) {
    border-radius: 0 50% 50% 0;
    .v-btn {
      background-color: #359c97 !important;
    }
  }

  :nth-child(1 of .v-date-picker-month__day--selected):nth-last-child(1
      of
      .v-date-picker-month__day--selected) {
    border-radius: 50% 50% 50% 50%;
    .v-btn {
      background-color: #359c97 !important;
    }
  }
}
</style>

<script setup lang="ts">
import { computed, ref, unref } from "vue";
import { useI18n } from "vue-i18n";

const { t } = useI18n();
const range = ref([]);
const menu = ref(false);
const model = defineModel<Date[]>();
const dates = computed({
  get: datesBetween,
  set: updateRange,
});

const dateRangeText = computed(() => {
  if (model.value == undefined || model.value.length == 0) {
    return t("date_range_picker.selection");
  }
  const [start, end] = unref(model);
  if (!!start && !!end) {
    return `${t("date_range_picker.from")} ${start.toLocaleDateString()} ${t(
      "date_range_picker.to"
    )} ${end.toLocaleDateString()}`;
  } else if (isToday(start)) {
    return t("date_range_picker.today");
  } else {
    return start.toLocaleDateString();
  }
});

function updateRange(date) {
  const [start, end] = unref(range);
  //if everything is null or everything is not
  if (!!start === !!end) {
    range.value = [date];
  } else if (date < start) {
    range.value = [date, start];
  } else if (date > start) {
    range.value = [start, date];
  }
}

function datesBetween() {
  if (range.value == undefined) {
    return [];
  }
  const [start, end] = unref(range);
  if (!!start && !!end) {
    const between = [];
    const currentDate = new Date(start);
    while (currentDate <= end) {
      between.push(new Date(currentDate));
      currentDate.setDate(currentDate.getDate() + 1);
    }
    return between;
  } else {
    return range.value;
  }
}

function isToday(date) {
  const today = new Date(Date.now());
  today.setHours(0, 0, 0, 0);
  return today.getTime() == date.getTime();
}

function save() {
  model.value = range.value;
  menu.value = false;
}

function cancel() {
  range.value = model.value || [];
  menu.value = false;
}
</script>
scipilot commented 3 months ago

Is there a planned release version or date for this? It has blocked my upgrade to Vue 3 + Vuetify 3 so I'd like to know when to return to the upgrade.

scipilot commented 3 months ago

It seems to be implemented here: https://vuetifyjs.com/en/api/v-date-picker/#props-multiple

multiple="range"

scipilot commented 3 months ago

Or here (still in Labs): https://vuetifyjs.com/en/components/date-inputs/#range