index.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. exports.__esModule = true;
  4. exports.default = void 0;
  5. var _raf = require("../utils/dom/raf");
  6. var _date = require("../utils/validate/date");
  7. var _scroll = require("../utils/dom/scroll");
  8. var _utils = require("./utils");
  9. var _popup = _interopRequireDefault(require("../popup"));
  10. var _button = _interopRequireDefault(require("../button"));
  11. var _toast = _interopRequireDefault(require("../toast"));
  12. var _Month = _interopRequireDefault(require("./components/Month"));
  13. var _Header = _interopRequireDefault(require("./components/Header"));
  14. // Utils
  15. // Components
  16. var _default2 = (0, _utils.createComponent)({
  17. props: {
  18. title: String,
  19. color: String,
  20. value: Boolean,
  21. readonly: Boolean,
  22. formatter: Function,
  23. rowHeight: [Number, String],
  24. confirmText: String,
  25. rangePrompt: String,
  26. defaultDate: [Date, Array],
  27. getContainer: [String, Function],
  28. allowSameDay: Boolean,
  29. confirmDisabledText: String,
  30. type: {
  31. type: String,
  32. default: 'single'
  33. },
  34. round: {
  35. type: Boolean,
  36. default: true
  37. },
  38. position: {
  39. type: String,
  40. default: 'bottom'
  41. },
  42. poppable: {
  43. type: Boolean,
  44. default: true
  45. },
  46. maxRange: {
  47. type: [Number, String],
  48. default: null
  49. },
  50. lazyRender: {
  51. type: Boolean,
  52. default: true
  53. },
  54. showMark: {
  55. type: Boolean,
  56. default: true
  57. },
  58. showTitle: {
  59. type: Boolean,
  60. default: true
  61. },
  62. showConfirm: {
  63. type: Boolean,
  64. default: true
  65. },
  66. showSubtitle: {
  67. type: Boolean,
  68. default: true
  69. },
  70. closeOnPopstate: {
  71. type: Boolean,
  72. default: true
  73. },
  74. closeOnClickOverlay: {
  75. type: Boolean,
  76. default: true
  77. },
  78. safeAreaInsetBottom: {
  79. type: Boolean,
  80. default: true
  81. },
  82. minDate: {
  83. type: Date,
  84. validator: _date.isDate,
  85. default: function _default() {
  86. return new Date();
  87. }
  88. },
  89. maxDate: {
  90. type: Date,
  91. validator: _date.isDate,
  92. default: function _default() {
  93. var now = new Date();
  94. return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate());
  95. }
  96. },
  97. firstDayOfWeek: {
  98. type: [Number, String],
  99. default: 0,
  100. validator: function validator(val) {
  101. return val >= 0 && val <= 6;
  102. }
  103. }
  104. },
  105. inject: {
  106. vanPopup: {
  107. default: null
  108. }
  109. },
  110. data: function data() {
  111. return {
  112. subtitle: '',
  113. currentDate: this.getInitialDate()
  114. };
  115. },
  116. computed: {
  117. months: function months() {
  118. var months = [];
  119. var cursor = new Date(this.minDate);
  120. cursor.setDate(1);
  121. do {
  122. months.push(new Date(cursor));
  123. cursor.setMonth(cursor.getMonth() + 1);
  124. } while ((0, _utils.compareMonth)(cursor, this.maxDate) !== 1);
  125. return months;
  126. },
  127. buttonDisabled: function buttonDisabled() {
  128. var type = this.type,
  129. currentDate = this.currentDate;
  130. if (currentDate) {
  131. if (type === 'range') {
  132. return !currentDate[0] || !currentDate[1];
  133. }
  134. if (type === 'multiple') {
  135. return !currentDate.length;
  136. }
  137. }
  138. return !currentDate;
  139. },
  140. dayOffset: function dayOffset() {
  141. return this.firstDayOfWeek ? this.firstDayOfWeek % 7 : 0;
  142. }
  143. },
  144. watch: {
  145. value: 'init',
  146. type: function type() {
  147. this.reset();
  148. },
  149. defaultDate: function defaultDate(val) {
  150. this.currentDate = val;
  151. this.scrollIntoView();
  152. }
  153. },
  154. mounted: function mounted() {
  155. this.init(); // https://github.com/vant-ui/vant/issues/9845
  156. if (!this.poppable) {
  157. var _this$vanPopup;
  158. (_this$vanPopup = this.vanPopup) == null ? void 0 : _this$vanPopup.$on('opened', this.onScroll);
  159. }
  160. },
  161. /* istanbul ignore next */
  162. activated: function activated() {
  163. this.init();
  164. },
  165. methods: {
  166. // @exposed-api
  167. reset: function reset(date) {
  168. if (date === void 0) {
  169. date = this.getInitialDate();
  170. }
  171. this.currentDate = date;
  172. this.scrollIntoView();
  173. },
  174. init: function init() {
  175. var _this = this;
  176. if (this.poppable && !this.value) {
  177. return;
  178. }
  179. this.$nextTick(function () {
  180. // add Math.floor to avoid decimal height issues
  181. // https://github.com/vant-ui/vant/issues/5640
  182. _this.bodyHeight = Math.floor(_this.$refs.body.getBoundingClientRect().height);
  183. _this.onScroll();
  184. _this.scrollIntoView();
  185. });
  186. },
  187. // @exposed-api
  188. scrollToDate: function scrollToDate(targetDate) {
  189. var _this2 = this;
  190. (0, _raf.raf)(function () {
  191. var displayed = _this2.value || !_this2.poppable;
  192. /* istanbul ignore if */
  193. if (!targetDate || !displayed) {
  194. return;
  195. }
  196. _this2.months.some(function (month, index) {
  197. if ((0, _utils.compareMonth)(month, targetDate) === 0) {
  198. var _this2$$refs = _this2.$refs,
  199. body = _this2$$refs.body,
  200. months = _this2$$refs.months;
  201. months[index].scrollIntoView(body);
  202. return true;
  203. }
  204. return false;
  205. });
  206. _this2.onScroll();
  207. });
  208. },
  209. // scroll to current month
  210. scrollIntoView: function scrollIntoView() {
  211. var currentDate = this.currentDate;
  212. if (currentDate) {
  213. var targetDate = this.type === 'single' ? currentDate : currentDate[0];
  214. this.scrollToDate(targetDate);
  215. }
  216. },
  217. getInitialDate: function getInitialDate() {
  218. var type = this.type,
  219. minDate = this.minDate,
  220. maxDate = this.maxDate,
  221. defaultDate = this.defaultDate;
  222. if (defaultDate === null) {
  223. return defaultDate;
  224. }
  225. var defaultVal = new Date();
  226. if ((0, _utils.compareDay)(defaultVal, minDate) === -1) {
  227. defaultVal = minDate;
  228. } else if ((0, _utils.compareDay)(defaultVal, maxDate) === 1) {
  229. defaultVal = maxDate;
  230. }
  231. if (type === 'range') {
  232. var _ref = defaultDate || [],
  233. startDay = _ref[0],
  234. endDay = _ref[1];
  235. return [startDay || defaultVal, endDay || (0, _utils.getNextDay)(defaultVal)];
  236. }
  237. if (type === 'multiple') {
  238. return defaultDate || [defaultVal];
  239. }
  240. return defaultDate || defaultVal;
  241. },
  242. // calculate the position of the elements
  243. // and find the elements that needs to be rendered
  244. onScroll: function onScroll() {
  245. var _this$$refs = this.$refs,
  246. body = _this$$refs.body,
  247. months = _this$$refs.months;
  248. var top = (0, _scroll.getScrollTop)(body);
  249. var bottom = top + this.bodyHeight;
  250. var heights = months.map(function (item) {
  251. return item.getHeight();
  252. });
  253. var heightSum = heights.reduce(function (a, b) {
  254. return a + b;
  255. }, 0); // iOS scroll bounce may exceed the range
  256. if (bottom > heightSum && top > 0) {
  257. return;
  258. }
  259. var height = 0;
  260. var currentMonth;
  261. var visibleRange = [-1, -1];
  262. for (var i = 0; i < months.length; i++) {
  263. var visible = height <= bottom && height + heights[i] >= top;
  264. if (visible) {
  265. visibleRange[1] = i;
  266. if (!currentMonth) {
  267. currentMonth = months[i];
  268. visibleRange[0] = i;
  269. }
  270. if (!months[i].showed) {
  271. months[i].showed = true;
  272. this.$emit('month-show', {
  273. date: months[i].date,
  274. title: months[i].title
  275. });
  276. }
  277. }
  278. height += heights[i];
  279. }
  280. months.forEach(function (month, index) {
  281. month.visible = index >= visibleRange[0] - 1 && index <= visibleRange[1] + 1;
  282. });
  283. /* istanbul ignore else */
  284. if (currentMonth) {
  285. this.subtitle = currentMonth.title;
  286. }
  287. },
  288. onClickDay: function onClickDay(item) {
  289. if (this.readonly) {
  290. return;
  291. }
  292. var date = item.date;
  293. var type = this.type,
  294. currentDate = this.currentDate;
  295. if (type === 'range') {
  296. if (!currentDate) {
  297. this.select([date, null]);
  298. return;
  299. }
  300. var startDay = currentDate[0],
  301. endDay = currentDate[1];
  302. if (startDay && !endDay) {
  303. var compareToStart = (0, _utils.compareDay)(date, startDay);
  304. if (compareToStart === 1) {
  305. this.select([startDay, date], true);
  306. } else if (compareToStart === -1) {
  307. this.select([date, null]);
  308. } else if (this.allowSameDay) {
  309. this.select([date, date], true);
  310. }
  311. } else {
  312. this.select([date, null]);
  313. }
  314. } else if (type === 'multiple') {
  315. if (!currentDate) {
  316. this.select([date]);
  317. return;
  318. }
  319. var selectedIndex;
  320. var selected = this.currentDate.some(function (dateItem, index) {
  321. var equal = (0, _utils.compareDay)(dateItem, date) === 0;
  322. if (equal) {
  323. selectedIndex = index;
  324. }
  325. return equal;
  326. });
  327. if (selected) {
  328. var _currentDate$splice = currentDate.splice(selectedIndex, 1),
  329. unselectedDate = _currentDate$splice[0];
  330. this.$emit('unselect', (0, _utils.copyDate)(unselectedDate));
  331. } else if (this.maxRange && currentDate.length >= this.maxRange) {
  332. (0, _toast.default)(this.rangePrompt || (0, _utils.t)('rangePrompt', this.maxRange));
  333. } else {
  334. this.select([].concat(currentDate, [date]));
  335. }
  336. } else {
  337. this.select(date, true);
  338. }
  339. },
  340. togglePopup: function togglePopup(val) {
  341. this.$emit('input', val);
  342. },
  343. select: function select(date, complete) {
  344. var _this3 = this;
  345. var emit = function emit(date) {
  346. _this3.currentDate = date;
  347. _this3.$emit('select', (0, _utils.copyDates)(_this3.currentDate));
  348. };
  349. if (complete && this.type === 'range') {
  350. var valid = this.checkRange(date);
  351. if (!valid) {
  352. // auto selected to max range if showConfirm
  353. if (this.showConfirm) {
  354. emit([date[0], (0, _utils.getDayByOffset)(date[0], this.maxRange - 1)]);
  355. } else {
  356. emit(date);
  357. }
  358. return;
  359. }
  360. }
  361. emit(date);
  362. if (complete && !this.showConfirm) {
  363. this.onConfirm();
  364. }
  365. },
  366. checkRange: function checkRange(date) {
  367. var maxRange = this.maxRange,
  368. rangePrompt = this.rangePrompt;
  369. if (maxRange && (0, _utils.calcDateNum)(date) > maxRange) {
  370. (0, _toast.default)(rangePrompt || (0, _utils.t)('rangePrompt', maxRange));
  371. return false;
  372. }
  373. return true;
  374. },
  375. onConfirm: function onConfirm() {
  376. this.$emit('confirm', (0, _utils.copyDates)(this.currentDate));
  377. },
  378. genMonth: function genMonth(date, index) {
  379. var h = this.$createElement;
  380. var showMonthTitle = index !== 0 || !this.showSubtitle;
  381. return h(_Month.default, {
  382. "ref": "months",
  383. "refInFor": true,
  384. "attrs": {
  385. "date": date,
  386. "type": this.type,
  387. "color": this.color,
  388. "minDate": this.minDate,
  389. "maxDate": this.maxDate,
  390. "showMark": this.showMark,
  391. "formatter": this.formatter,
  392. "rowHeight": this.rowHeight,
  393. "lazyRender": this.lazyRender,
  394. "currentDate": this.currentDate,
  395. "showSubtitle": this.showSubtitle,
  396. "allowSameDay": this.allowSameDay,
  397. "showMonthTitle": showMonthTitle,
  398. "firstDayOfWeek": this.dayOffset
  399. },
  400. "scopedSlots": {
  401. 'top-info': this.$scopedSlots['top-info'],
  402. 'bottom-info': this.$scopedSlots['bottom-info']
  403. },
  404. "on": {
  405. "click": this.onClickDay
  406. }
  407. });
  408. },
  409. genFooterContent: function genFooterContent() {
  410. var h = this.$createElement;
  411. var slot = this.slots('footer');
  412. if (slot) {
  413. return slot;
  414. }
  415. if (this.showConfirm) {
  416. var text = this.buttonDisabled ? this.confirmDisabledText : this.confirmText;
  417. return h(_button.default, {
  418. "attrs": {
  419. "round": true,
  420. "block": true,
  421. "type": "danger",
  422. "color": this.color,
  423. "disabled": this.buttonDisabled,
  424. "nativeType": "button"
  425. },
  426. "class": (0, _utils.bem)('confirm'),
  427. "on": {
  428. "click": this.onConfirm
  429. }
  430. }, [text || (0, _utils.t)('confirm')]);
  431. }
  432. },
  433. genFooter: function genFooter() {
  434. var h = this.$createElement;
  435. return h("div", {
  436. "class": (0, _utils.bem)('footer', {
  437. unfit: !this.safeAreaInsetBottom
  438. })
  439. }, [this.genFooterContent()]);
  440. },
  441. genCalendar: function genCalendar() {
  442. var _this4 = this;
  443. var h = this.$createElement;
  444. return h("div", {
  445. "class": (0, _utils.bem)()
  446. }, [h(_Header.default, {
  447. "attrs": {
  448. "title": this.title,
  449. "showTitle": this.showTitle,
  450. "subtitle": this.subtitle,
  451. "showSubtitle": this.showSubtitle,
  452. "firstDayOfWeek": this.dayOffset
  453. },
  454. "scopedSlots": {
  455. title: function title() {
  456. return _this4.slots('title');
  457. }
  458. }
  459. }), h("div", {
  460. "ref": "body",
  461. "class": (0, _utils.bem)('body'),
  462. "on": {
  463. "scroll": this.onScroll
  464. }
  465. }, [this.months.map(this.genMonth)]), this.genFooter()]);
  466. }
  467. },
  468. render: function render() {
  469. var _this5 = this;
  470. var h = arguments[0];
  471. if (this.poppable) {
  472. var _attrs;
  473. var createListener = function createListener(name) {
  474. return function () {
  475. return _this5.$emit(name);
  476. };
  477. };
  478. return h(_popup.default, {
  479. "attrs": (_attrs = {
  480. "round": true,
  481. "value": this.value
  482. }, _attrs["round"] = this.round, _attrs["position"] = this.position, _attrs["closeable"] = this.showTitle || this.showSubtitle, _attrs["getContainer"] = this.getContainer, _attrs["closeOnPopstate"] = this.closeOnPopstate, _attrs["closeOnClickOverlay"] = this.closeOnClickOverlay, _attrs),
  483. "class": (0, _utils.bem)('popup'),
  484. "on": {
  485. "input": this.togglePopup,
  486. "open": createListener('open'),
  487. "opened": createListener('opened'),
  488. "close": createListener('close'),
  489. "closed": createListener('closed')
  490. }
  491. }, [this.genCalendar()]);
  492. }
  493. return this.genCalendar();
  494. }
  495. });
  496. exports.default = _default2;