calendar.mjs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Composables
  2. import { getWeek, useDate } from "./date/date.mjs";
  3. import { useProxiedModel } from "./proxiedModel.mjs"; // Utilities
  4. import { computed } from 'vue';
  5. import { propsFactory, wrapInArray } from "../util/index.mjs"; // Types
  6. // Types
  7. // Composables
  8. export const makeCalendarProps = propsFactory({
  9. allowedDates: [Array, Function],
  10. disabled: Boolean,
  11. displayValue: null,
  12. modelValue: Array,
  13. month: [Number, String],
  14. max: null,
  15. min: null,
  16. showAdjacentMonths: Boolean,
  17. year: [Number, String],
  18. weekdays: {
  19. type: Array,
  20. default: () => [0, 1, 2, 3, 4, 5, 6]
  21. },
  22. weeksInMonth: {
  23. type: String,
  24. default: 'dynamic'
  25. },
  26. firstDayOfWeek: [Number, String]
  27. }, 'calendar');
  28. export function useCalendar(props) {
  29. const adapter = useDate();
  30. const model = useProxiedModel(props, 'modelValue', [], v => wrapInArray(v));
  31. const displayValue = computed(() => {
  32. if (props.displayValue) return adapter.date(props.displayValue);
  33. if (model.value.length > 0) return adapter.date(model.value[0]);
  34. if (props.min) return adapter.date(props.min);
  35. if (Array.isArray(props.allowedDates)) return adapter.date(props.allowedDates[0]);
  36. return adapter.date();
  37. });
  38. const year = useProxiedModel(props, 'year', undefined, v => {
  39. const value = v != null ? Number(v) : adapter.getYear(displayValue.value);
  40. return adapter.startOfYear(adapter.setYear(adapter.date(), value));
  41. }, v => adapter.getYear(v));
  42. const month = useProxiedModel(props, 'month', undefined, v => {
  43. const value = v != null ? Number(v) : adapter.getMonth(displayValue.value);
  44. const date = adapter.setYear(adapter.startOfMonth(adapter.date()), adapter.getYear(year.value));
  45. return adapter.setMonth(date, value);
  46. }, v => adapter.getMonth(v));
  47. const weekDays = computed(() => {
  48. const firstDayOfWeek = Number(props.firstDayOfWeek ?? 0);
  49. return props.weekdays.map(day => (day + firstDayOfWeek) % 7);
  50. });
  51. const weeksInMonth = computed(() => {
  52. const weeks = adapter.getWeekArray(month.value, props.firstDayOfWeek);
  53. const days = weeks.flat();
  54. // Make sure there's always 6 weeks in month (6 * 7 days)
  55. // if weeksInMonth is 'static'
  56. const daysInMonth = 6 * 7;
  57. if (props.weeksInMonth === 'static' && days.length < daysInMonth) {
  58. const lastDay = days[days.length - 1];
  59. let week = [];
  60. for (let day = 1; day <= daysInMonth - days.length; day++) {
  61. week.push(adapter.addDays(lastDay, day));
  62. if (day % 7 === 0) {
  63. weeks.push(week);
  64. week = [];
  65. }
  66. }
  67. }
  68. return weeks;
  69. });
  70. function genDays(days, today) {
  71. return days.filter(date => {
  72. return weekDays.value.includes(adapter.toJsDate(date).getDay());
  73. }).map((date, index) => {
  74. const isoDate = adapter.toISO(date);
  75. const isAdjacent = !adapter.isSameMonth(date, month.value);
  76. const isStart = adapter.isSameDay(date, adapter.startOfMonth(month.value));
  77. const isEnd = adapter.isSameDay(date, adapter.endOfMonth(month.value));
  78. const isSame = adapter.isSameDay(date, month.value);
  79. return {
  80. date,
  81. isoDate,
  82. formatted: adapter.format(date, 'keyboardDate'),
  83. year: adapter.getYear(date),
  84. month: adapter.getMonth(date),
  85. isDisabled: isDisabled(date),
  86. isWeekStart: index % 7 === 0,
  87. isWeekEnd: index % 7 === 6,
  88. isToday: adapter.isSameDay(date, today),
  89. isAdjacent,
  90. isHidden: isAdjacent && !props.showAdjacentMonths,
  91. isStart,
  92. isSelected: model.value.some(value => adapter.isSameDay(date, value)),
  93. isEnd,
  94. isSame,
  95. localized: adapter.format(date, 'dayOfMonth')
  96. };
  97. });
  98. }
  99. const daysInWeek = computed(() => {
  100. const lastDay = adapter.startOfWeek(displayValue.value, props.firstDayOfWeek);
  101. const week = [];
  102. for (let day = 0; day <= 6; day++) {
  103. week.push(adapter.addDays(lastDay, day));
  104. }
  105. const today = adapter.date();
  106. return genDays(week, today);
  107. });
  108. const daysInMonth = computed(() => {
  109. const days = weeksInMonth.value.flat();
  110. const today = adapter.date();
  111. return genDays(days, today);
  112. });
  113. const weekNumbers = computed(() => {
  114. return weeksInMonth.value.map(week => {
  115. return week.length ? getWeek(adapter, week[0]) : null;
  116. });
  117. });
  118. function isDisabled(value) {
  119. if (props.disabled) return true;
  120. const date = adapter.date(value);
  121. if (props.min && adapter.isAfter(adapter.date(props.min), date)) return true;
  122. if (props.max && adapter.isAfter(date, adapter.date(props.max))) return true;
  123. if (Array.isArray(props.allowedDates) && props.allowedDates.length > 0) {
  124. return !props.allowedDates.some(d => adapter.isSameDay(adapter.date(d), date));
  125. }
  126. if (typeof props.allowedDates === 'function') {
  127. return !props.allowedDates(date);
  128. }
  129. return false;
  130. }
  131. return {
  132. displayValue,
  133. daysInMonth,
  134. daysInWeek,
  135. genDays,
  136. model,
  137. weeksInMonth,
  138. weekDays,
  139. weekNumbers
  140. };
  141. }
  142. //# sourceMappingURL=calendar.mjs.map