useRangeValue.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. "use strict";
  2. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  3. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = useRangeValue;
  8. exports.useInnerValue = useInnerValue;
  9. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  10. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  11. var _rcUtil = require("rc-util");
  12. var React = _interopRequireWildcard(require("react"));
  13. var _useSyncState5 = _interopRequireDefault(require("../../hooks/useSyncState"));
  14. var _dateUtil = require("../../utils/dateUtil");
  15. var _miscUtil = require("../../utils/miscUtil");
  16. var _useLockEffect = _interopRequireDefault(require("./useLockEffect"));
  17. var EMPTY_VALUE = [];
  18. // Submit Logic:
  19. // * ✅ Value:
  20. // * merged value using controlled value, if not, use stateValue
  21. // * When merged value change, [1] resync calendar value and submit value
  22. // * ✅ Calender Value:
  23. // * 💻 When user typing is validate, change the calendar value
  24. // * 🌅 When user click on the panel, change the calendar value
  25. // * Submit Value:
  26. // * 💻 When user blur the input, flush calendar value to submit value
  27. // * 🌅 When user click on the panel is no needConfirm, flush calendar value to submit value
  28. // * 🌅 When user click on the panel is needConfirm and click OK, flush calendar value to submit value
  29. // * Blur logic & close logic:
  30. // * ✅ For value, always try flush submit
  31. // * ✅ If `needConfirm`, reset as [1]
  32. // * Else (`!needConfirm`)
  33. // * If has another index field, active another index
  34. // * ✅ Flush submit:
  35. // * If all the start & end field is confirmed or all blur or panel closed
  36. // * Update `needSubmit` mark to true
  37. // * trigger onChange by `needSubmit` and update stateValue
  38. function useUtil(generateConfig, locale, formatList) {
  39. var getDateTexts = function getDateTexts(dates) {
  40. return dates.map(function (date) {
  41. return (0, _dateUtil.formatValue)(date, {
  42. generateConfig: generateConfig,
  43. locale: locale,
  44. format: formatList[0]
  45. });
  46. });
  47. };
  48. var isSameDates = function isSameDates(source, target) {
  49. var maxLen = Math.max(source.length, target.length);
  50. var diffIndex = -1;
  51. for (var i = 0; i < maxLen; i += 1) {
  52. var prev = source[i] || null;
  53. var next = target[i] || null;
  54. if (prev !== next && !(0, _dateUtil.isSameTimestamp)(generateConfig, prev, next)) {
  55. diffIndex = i;
  56. break;
  57. }
  58. }
  59. return [diffIndex < 0, diffIndex !== 0];
  60. };
  61. return [getDateTexts, isSameDates];
  62. }
  63. function orderDates(dates, generateConfig) {
  64. return (0, _toConsumableArray2.default)(dates).sort(function (a, b) {
  65. return generateConfig.isAfter(a, b) ? 1 : -1;
  66. });
  67. }
  68. /**
  69. * Used for internal value management.
  70. * It should always use `mergedValue` in render logic
  71. */
  72. function useCalendarValue(mergedValue) {
  73. var _useSyncState = (0, _useSyncState5.default)(mergedValue),
  74. _useSyncState2 = (0, _slicedToArray2.default)(_useSyncState, 2),
  75. calendarValue = _useSyncState2[0],
  76. setCalendarValue = _useSyncState2[1];
  77. /** Sync calendarValue & submitValue back with value */
  78. var syncWithValue = (0, _rcUtil.useEvent)(function () {
  79. setCalendarValue(mergedValue);
  80. });
  81. React.useEffect(function () {
  82. syncWithValue();
  83. }, [mergedValue]);
  84. return [calendarValue, setCalendarValue];
  85. }
  86. /**
  87. * Control the internal `value` align with prop `value` and provide a temp `calendarValue` for ui.
  88. * `calendarValue` will be reset when blur & focus & open.
  89. */
  90. function useInnerValue(generateConfig, locale, formatList, /** Used for RangePicker. `true` means [DateType, DateType] or will be DateType[] */
  91. rangeValue,
  92. /**
  93. * Trigger order when trigger calendar value change.
  94. * This should only used in SinglePicker with `multiple` mode.
  95. * So when `rangeValue` is `true`, order will be ignored.
  96. */
  97. order, defaultValue, value, onCalendarChange, onOk) {
  98. // This is the root value which will sync with controlled or uncontrolled value
  99. var _useMergedState = (0, _rcUtil.useMergedState)(defaultValue, {
  100. value: value
  101. }),
  102. _useMergedState2 = (0, _slicedToArray2.default)(_useMergedState, 2),
  103. innerValue = _useMergedState2[0],
  104. setInnerValue = _useMergedState2[1];
  105. var mergedValue = innerValue || EMPTY_VALUE;
  106. // ========================= Inner Values =========================
  107. var _useCalendarValue = useCalendarValue(mergedValue),
  108. _useCalendarValue2 = (0, _slicedToArray2.default)(_useCalendarValue, 2),
  109. calendarValue = _useCalendarValue2[0],
  110. setCalendarValue = _useCalendarValue2[1];
  111. // ============================ Change ============================
  112. var _useUtil = useUtil(generateConfig, locale, formatList),
  113. _useUtil2 = (0, _slicedToArray2.default)(_useUtil, 2),
  114. getDateTexts = _useUtil2[0],
  115. isSameDates = _useUtil2[1];
  116. var triggerCalendarChange = (0, _rcUtil.useEvent)(function (nextCalendarValues) {
  117. var clone = (0, _toConsumableArray2.default)(nextCalendarValues);
  118. if (rangeValue) {
  119. for (var i = 0; i < 2; i += 1) {
  120. clone[i] = clone[i] || null;
  121. }
  122. } else if (order) {
  123. clone = orderDates(clone.filter(function (date) {
  124. return date;
  125. }), generateConfig);
  126. }
  127. // Update merged value
  128. var _isSameDates = isSameDates(calendarValue(), clone),
  129. _isSameDates2 = (0, _slicedToArray2.default)(_isSameDates, 2),
  130. isSameMergedDates = _isSameDates2[0],
  131. isSameStart = _isSameDates2[1];
  132. if (!isSameMergedDates) {
  133. setCalendarValue(clone);
  134. // Trigger calendar change event
  135. if (onCalendarChange) {
  136. var cellTexts = getDateTexts(clone);
  137. onCalendarChange(clone, cellTexts, {
  138. range: isSameStart ? 'end' : 'start'
  139. });
  140. }
  141. }
  142. });
  143. var triggerOk = function triggerOk() {
  144. if (onOk) {
  145. onOk(calendarValue());
  146. }
  147. };
  148. return [mergedValue, setInnerValue, calendarValue, triggerCalendarChange, triggerOk];
  149. }
  150. function useRangeValue(info, mergedValue, setInnerValue, getCalendarValue, triggerCalendarChange, disabled, formatList, focused, open, isInvalidateDate) {
  151. var generateConfig = info.generateConfig,
  152. locale = info.locale,
  153. picker = info.picker,
  154. onChange = info.onChange,
  155. allowEmpty = info.allowEmpty,
  156. order = info.order;
  157. var orderOnChange = disabled.some(function (d) {
  158. return d;
  159. }) ? false : order;
  160. // ============================= Util =============================
  161. var _useUtil3 = useUtil(generateConfig, locale, formatList),
  162. _useUtil4 = (0, _slicedToArray2.default)(_useUtil3, 2),
  163. getDateTexts = _useUtil4[0],
  164. isSameDates = _useUtil4[1];
  165. // ============================ Values ============================
  166. // Used for trigger `onChange` event.
  167. // Record current value which is wait for submit.
  168. var _useSyncState3 = (0, _useSyncState5.default)(mergedValue),
  169. _useSyncState4 = (0, _slicedToArray2.default)(_useSyncState3, 2),
  170. submitValue = _useSyncState4[0],
  171. setSubmitValue = _useSyncState4[1];
  172. /** Sync calendarValue & submitValue back with value */
  173. var syncWithValue = (0, _rcUtil.useEvent)(function () {
  174. setSubmitValue(mergedValue);
  175. });
  176. React.useEffect(function () {
  177. syncWithValue();
  178. }, [mergedValue]);
  179. // ============================ Submit ============================
  180. var triggerSubmit = (0, _rcUtil.useEvent)(function (nextValue) {
  181. var isNullValue = nextValue === null;
  182. var clone = (0, _toConsumableArray2.default)(nextValue || submitValue());
  183. // Fill null value
  184. if (isNullValue) {
  185. var maxLen = Math.max(disabled.length, clone.length);
  186. for (var i = 0; i < maxLen; i += 1) {
  187. if (!disabled[i]) {
  188. clone[i] = null;
  189. }
  190. }
  191. }
  192. // Only when exist value to sort
  193. if (orderOnChange && clone[0] && clone[1]) {
  194. clone = orderDates(clone, generateConfig);
  195. }
  196. // Sync `calendarValue`
  197. triggerCalendarChange(clone);
  198. // ========= Validate check =========
  199. var _clone = clone,
  200. _clone2 = (0, _slicedToArray2.default)(_clone, 2),
  201. start = _clone2[0],
  202. end = _clone2[1];
  203. // >>> Empty
  204. var startEmpty = !start;
  205. var endEmpty = !end;
  206. var validateEmptyDateRange = allowEmpty ?
  207. // Validate empty start
  208. (!startEmpty || allowEmpty[0]) && (
  209. // Validate empty end
  210. !endEmpty || allowEmpty[1]) : true;
  211. // >>> Order
  212. var validateOrder = !order || startEmpty || endEmpty || (0, _dateUtil.isSame)(generateConfig, locale, start, end, picker) || generateConfig.isAfter(end, start);
  213. // >>> Invalid
  214. var validateDates =
  215. // Validate start
  216. (disabled[0] || !start || !isInvalidateDate(start, {
  217. activeIndex: 0
  218. })) && (
  219. // Validate end
  220. disabled[1] || !end || !isInvalidateDate(end, {
  221. from: start,
  222. activeIndex: 1
  223. }));
  224. // >>> Result
  225. var allPassed =
  226. // Null value is from clear button
  227. isNullValue ||
  228. // Normal check
  229. validateEmptyDateRange && validateOrder && validateDates;
  230. if (allPassed) {
  231. // Sync value with submit value
  232. setInnerValue(clone);
  233. var _isSameDates3 = isSameDates(clone, mergedValue),
  234. _isSameDates4 = (0, _slicedToArray2.default)(_isSameDates3, 1),
  235. isSameMergedDates = _isSameDates4[0];
  236. // Trigger `onChange` if needed
  237. if (onChange && !isSameMergedDates) {
  238. onChange(
  239. // Return null directly if all date are empty
  240. isNullValue && clone.every(function (val) {
  241. return !val;
  242. }) ? null : clone, getDateTexts(clone));
  243. }
  244. }
  245. return allPassed;
  246. });
  247. // ========================= Flush Submit =========================
  248. var flushSubmit = (0, _rcUtil.useEvent)(function (index, needTriggerChange) {
  249. var nextSubmitValue = (0, _miscUtil.fillIndex)(submitValue(), index, getCalendarValue()[index]);
  250. setSubmitValue(nextSubmitValue);
  251. if (needTriggerChange) {
  252. triggerSubmit();
  253. }
  254. });
  255. // ============================ Effect ============================
  256. // All finished action trigger after 2 frames
  257. var interactiveFinished = !focused && !open;
  258. (0, _useLockEffect.default)(!interactiveFinished, function () {
  259. if (interactiveFinished) {
  260. // Always try to trigger submit first
  261. triggerSubmit();
  262. // Trigger calendar change since this is a effect reset
  263. // https://github.com/ant-design/ant-design/issues/22351
  264. triggerCalendarChange(mergedValue);
  265. // Sync with value anyway
  266. syncWithValue();
  267. }
  268. }, 2);
  269. // ============================ Return ============================
  270. return [flushSubmit, triggerSubmit];
  271. }