b52e77168d151d79e013d9994a4bb7c0bc4f1e9e7e82d7c2bea6f6a6e637141250ca0edb96674baf029a7fd21552007b3a85cffe109791bb37a3ac8f7a7487 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. import { ref, computed, unref, watch, nextTick } from 'vue';
  2. import dayjs from 'dayjs';
  3. import { flatten } from 'lodash-unified';
  4. import { buildPickerTable } from '../utils.mjs';
  5. import { useLocale } from '../../../../hooks/use-locale/index.mjs';
  6. import { castArray } from '../../../../utils/arrays.mjs';
  7. import { useNamespace } from '../../../../hooks/use-namespace/index.mjs';
  8. import { isArray } from '@vue/shared';
  9. const isNormalDay = (type = "") => {
  10. return ["normal", "today"].includes(type);
  11. };
  12. const useBasicDateTable = (props, emit) => {
  13. const { lang } = useLocale();
  14. const tbodyRef = ref();
  15. const currentCellRef = ref();
  16. const lastRow = ref();
  17. const lastColumn = ref();
  18. const tableRows = ref([[], [], [], [], [], []]);
  19. let focusWithClick = false;
  20. const firstDayOfWeek = props.date.$locale().weekStart || 7;
  21. const WEEKS_CONSTANT = props.date.locale("en").localeData().weekdaysShort().map((_) => _.toLowerCase());
  22. const offsetDay = computed(() => {
  23. return firstDayOfWeek > 3 ? 7 - firstDayOfWeek : -firstDayOfWeek;
  24. });
  25. const startDate = computed(() => {
  26. const startDayOfMonth = props.date.startOf("month");
  27. return startDayOfMonth.subtract(startDayOfMonth.day() || 7, "day");
  28. });
  29. const WEEKS = computed(() => {
  30. return WEEKS_CONSTANT.concat(WEEKS_CONSTANT).slice(firstDayOfWeek, firstDayOfWeek + 7);
  31. });
  32. const hasCurrent = computed(() => {
  33. return flatten(unref(rows)).some((row) => {
  34. return row.isCurrent;
  35. });
  36. });
  37. const days = computed(() => {
  38. const startOfMonth = props.date.startOf("month");
  39. const startOfMonthDay = startOfMonth.day() || 7;
  40. const dateCountOfMonth = startOfMonth.daysInMonth();
  41. const dateCountOfLastMonth = startOfMonth.subtract(1, "month").daysInMonth();
  42. return {
  43. startOfMonthDay,
  44. dateCountOfMonth,
  45. dateCountOfLastMonth
  46. };
  47. });
  48. const selectedDate = computed(() => {
  49. return props.selectionMode === "dates" ? castArray(props.parsedValue) : [];
  50. });
  51. const setDateText = (cell, { count, rowIndex, columnIndex }) => {
  52. const { startOfMonthDay, dateCountOfMonth, dateCountOfLastMonth } = unref(days);
  53. const offset = unref(offsetDay);
  54. if (rowIndex >= 0 && rowIndex <= 1) {
  55. const numberOfDaysFromPreviousMonth = startOfMonthDay + offset < 0 ? 7 + startOfMonthDay + offset : startOfMonthDay + offset;
  56. if (columnIndex + rowIndex * 7 >= numberOfDaysFromPreviousMonth) {
  57. cell.text = count;
  58. return true;
  59. } else {
  60. cell.text = dateCountOfLastMonth - (numberOfDaysFromPreviousMonth - columnIndex % 7) + 1 + rowIndex * 7;
  61. cell.type = "prev-month";
  62. }
  63. } else {
  64. if (count <= dateCountOfMonth) {
  65. cell.text = count;
  66. } else {
  67. cell.text = count - dateCountOfMonth;
  68. cell.type = "next-month";
  69. }
  70. return true;
  71. }
  72. return false;
  73. };
  74. const setCellMetadata = (cell, { columnIndex, rowIndex }, count) => {
  75. const { disabledDate, cellClassName } = props;
  76. const _selectedDate = unref(selectedDate);
  77. const shouldIncrement = setDateText(cell, { count, rowIndex, columnIndex });
  78. const cellDate = cell.dayjs.toDate();
  79. cell.selected = _selectedDate.find((d) => d.isSame(cell.dayjs, "day"));
  80. cell.isSelected = !!cell.selected;
  81. cell.isCurrent = isCurrent(cell);
  82. cell.disabled = disabledDate == null ? void 0 : disabledDate(cellDate);
  83. cell.customClass = cellClassName == null ? void 0 : cellClassName(cellDate);
  84. return shouldIncrement;
  85. };
  86. const setRowMetadata = (row) => {
  87. if (props.selectionMode === "week") {
  88. const [start, end] = props.showWeekNumber ? [1, 7] : [0, 6];
  89. const isActive = isWeekActive(row[start + 1]);
  90. row[start].inRange = isActive;
  91. row[start].start = isActive;
  92. row[end].inRange = isActive;
  93. row[end].end = isActive;
  94. }
  95. };
  96. const rows = computed(() => {
  97. const { minDate, maxDate, rangeState, showWeekNumber } = props;
  98. const offset = unref(offsetDay);
  99. const rows_ = unref(tableRows);
  100. const dateUnit = "day";
  101. let count = 1;
  102. buildPickerTable({ row: 6, column: 7 }, rows_, {
  103. startDate: minDate,
  104. columnIndexOffset: showWeekNumber ? 1 : 0,
  105. nextEndDate: rangeState.endDate || maxDate || rangeState.selecting && minDate || null,
  106. now: dayjs().locale(unref(lang)).startOf(dateUnit),
  107. unit: dateUnit,
  108. relativeDateGetter: (idx) => unref(startDate).add(idx - offset, dateUnit),
  109. setCellMetadata: (...args) => {
  110. if (setCellMetadata(...args, count)) {
  111. count += 1;
  112. }
  113. },
  114. setRowMetadata
  115. });
  116. if (showWeekNumber) {
  117. for (let rowIndex = 0; rowIndex < 6; rowIndex++) {
  118. if (rows_[rowIndex][1].dayjs) {
  119. rows_[rowIndex][0] = {
  120. type: "week",
  121. text: rows_[rowIndex][1].dayjs.week()
  122. };
  123. }
  124. }
  125. }
  126. return rows_;
  127. });
  128. watch(() => props.date, async () => {
  129. var _a;
  130. if ((_a = unref(tbodyRef)) == null ? void 0 : _a.contains(document.activeElement)) {
  131. await nextTick();
  132. await focus();
  133. }
  134. });
  135. const focus = async () => {
  136. var _a;
  137. return (_a = unref(currentCellRef)) == null ? void 0 : _a.focus();
  138. };
  139. const isCurrent = (cell) => {
  140. return props.selectionMode === "date" && isNormalDay(cell.type) && cellMatchesDate(cell, props.parsedValue);
  141. };
  142. const cellMatchesDate = (cell, date) => {
  143. if (!date)
  144. return false;
  145. return dayjs(date).locale(unref(lang)).isSame(props.date.date(Number(cell.text)), "day");
  146. };
  147. const getDateOfCell = (row, column) => {
  148. const offsetFromStart = row * 7 + (column - (props.showWeekNumber ? 1 : 0)) - unref(offsetDay);
  149. return unref(startDate).add(offsetFromStart, "day");
  150. };
  151. const handleMouseMove = (event) => {
  152. var _a;
  153. if (!props.rangeState.selecting)
  154. return;
  155. let target = event.target;
  156. if (target.tagName === "SPAN") {
  157. target = (_a = target.parentNode) == null ? void 0 : _a.parentNode;
  158. }
  159. if (target.tagName === "DIV") {
  160. target = target.parentNode;
  161. }
  162. if (target.tagName !== "TD")
  163. return;
  164. const row = target.parentNode.rowIndex - 1;
  165. const column = target.cellIndex;
  166. if (unref(rows)[row][column].disabled)
  167. return;
  168. if (row !== unref(lastRow) || column !== unref(lastColumn)) {
  169. lastRow.value = row;
  170. lastColumn.value = column;
  171. emit("changerange", {
  172. selecting: true,
  173. endDate: getDateOfCell(row, column)
  174. });
  175. }
  176. };
  177. const isSelectedCell = (cell) => {
  178. return !unref(hasCurrent) && (cell == null ? void 0 : cell.text) === 1 && cell.type === "normal" || cell.isCurrent;
  179. };
  180. const handleFocus = (event) => {
  181. if (focusWithClick || unref(hasCurrent) || props.selectionMode !== "date")
  182. return;
  183. handlePickDate(event, true);
  184. };
  185. const handleMouseDown = (event) => {
  186. const target = event.target.closest("td");
  187. if (!target)
  188. return;
  189. focusWithClick = true;
  190. };
  191. const handleMouseUp = (event) => {
  192. const target = event.target.closest("td");
  193. if (!target)
  194. return;
  195. focusWithClick = false;
  196. };
  197. const handleRangePick = (newDate) => {
  198. if (!props.rangeState.selecting || !props.minDate) {
  199. emit("pick", { minDate: newDate, maxDate: null });
  200. emit("select", true);
  201. } else {
  202. if (newDate >= props.minDate) {
  203. emit("pick", { minDate: props.minDate, maxDate: newDate });
  204. } else {
  205. emit("pick", { minDate: newDate, maxDate: props.minDate });
  206. }
  207. emit("select", false);
  208. }
  209. };
  210. const handleWeekPick = (newDate) => {
  211. const weekNumber = newDate.week();
  212. const value = `${newDate.year()}w${weekNumber}`;
  213. emit("pick", {
  214. year: newDate.year(),
  215. week: weekNumber,
  216. value,
  217. date: newDate.startOf("week")
  218. });
  219. };
  220. const handleDatesPick = (newDate, selected) => {
  221. const newValue = selected ? castArray(props.parsedValue).filter((d) => (d == null ? void 0 : d.valueOf()) !== newDate.valueOf()) : castArray(props.parsedValue).concat([newDate]);
  222. emit("pick", newValue);
  223. };
  224. const handlePickDate = (event, isKeyboardMovement = false) => {
  225. if (props.disabled)
  226. return;
  227. const target = event.target.closest("td");
  228. if (!target)
  229. return;
  230. const row = target.parentNode.rowIndex - 1;
  231. const column = target.cellIndex;
  232. const cell = unref(rows)[row][column];
  233. if (cell.disabled || cell.type === "week")
  234. return;
  235. const newDate = getDateOfCell(row, column);
  236. switch (props.selectionMode) {
  237. case "range": {
  238. handleRangePick(newDate);
  239. break;
  240. }
  241. case "date": {
  242. emit("pick", newDate, isKeyboardMovement);
  243. break;
  244. }
  245. case "week": {
  246. handleWeekPick(newDate);
  247. break;
  248. }
  249. case "dates": {
  250. handleDatesPick(newDate, !!cell.selected);
  251. break;
  252. }
  253. }
  254. };
  255. const isWeekActive = (cell) => {
  256. if (props.selectionMode !== "week")
  257. return false;
  258. let newDate = props.date.startOf("day");
  259. if (cell.type === "prev-month") {
  260. newDate = newDate.subtract(1, "month");
  261. }
  262. if (cell.type === "next-month") {
  263. newDate = newDate.add(1, "month");
  264. }
  265. newDate = newDate.date(Number.parseInt(cell.text, 10));
  266. if (props.parsedValue && !isArray(props.parsedValue)) {
  267. const dayOffset = (props.parsedValue.day() - firstDayOfWeek + 7) % 7 - 1;
  268. const weekDate = props.parsedValue.subtract(dayOffset, "day");
  269. return weekDate.isSame(newDate, "day");
  270. }
  271. return false;
  272. };
  273. return {
  274. WEEKS,
  275. rows,
  276. tbodyRef,
  277. currentCellRef,
  278. focus,
  279. isCurrent,
  280. isWeekActive,
  281. isSelectedCell,
  282. handlePickDate,
  283. handleMouseUp,
  284. handleMouseDown,
  285. handleMouseMove,
  286. handleFocus
  287. };
  288. };
  289. const useBasicDateTableDOM = (props, {
  290. isCurrent,
  291. isWeekActive
  292. }) => {
  293. const ns = useNamespace("date-table");
  294. const { t } = useLocale();
  295. const tableKls = computed(() => [
  296. ns.b(),
  297. { "is-week-mode": props.selectionMode === "week" && !props.disabled }
  298. ]);
  299. const tableLabel = computed(() => t("el.datepicker.dateTablePrompt"));
  300. const getCellClasses = (cell) => {
  301. const classes = [];
  302. if (isNormalDay(cell.type) && !cell.disabled) {
  303. classes.push("available");
  304. if (cell.type === "today") {
  305. classes.push("today");
  306. }
  307. } else {
  308. classes.push(cell.type);
  309. }
  310. if (isCurrent(cell)) {
  311. classes.push("current");
  312. }
  313. if (cell.inRange && (isNormalDay(cell.type) || props.selectionMode === "week")) {
  314. classes.push("in-range");
  315. if (cell.start) {
  316. classes.push("start-date");
  317. }
  318. if (cell.end) {
  319. classes.push("end-date");
  320. }
  321. }
  322. if (cell.disabled || props.disabled) {
  323. classes.push("disabled");
  324. }
  325. if (cell.selected) {
  326. classes.push("selected");
  327. }
  328. if (cell.customClass) {
  329. classes.push(cell.customClass);
  330. }
  331. return classes.join(" ");
  332. };
  333. const getRowKls = (cell) => [
  334. ns.e("row"),
  335. { current: isWeekActive(cell) }
  336. ];
  337. return {
  338. tableKls,
  339. tableLabel,
  340. weekHeaderClass: ns.e("week-header"),
  341. getCellClasses,
  342. getRowKls,
  343. t
  344. };
  345. };
  346. export { useBasicDateTable, useBasicDateTableDOM };
  347. //# sourceMappingURL=use-basic-date-table.mjs.map