index.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  4. import classNames from 'classnames';
  5. import ResizeObserver from 'rc-resize-observer';
  6. import * as React from 'react';
  7. import { toArray } from "../../utils/miscUtil";
  8. import PickerContext from "../context";
  9. import Footer from "./Footer";
  10. import PopupPanel from "./PopupPanel";
  11. import PresetPanel from "./PresetPanel";
  12. export default function Popup(props) {
  13. var panelRender = props.panelRender,
  14. internalMode = props.internalMode,
  15. picker = props.picker,
  16. showNow = props.showNow,
  17. range = props.range,
  18. multiple = props.multiple,
  19. _props$activeInfo = props.activeInfo,
  20. activeInfo = _props$activeInfo === void 0 ? [0, 0, 0] : _props$activeInfo,
  21. presets = props.presets,
  22. onPresetHover = props.onPresetHover,
  23. onPresetSubmit = props.onPresetSubmit,
  24. onFocus = props.onFocus,
  25. onBlur = props.onBlur,
  26. onPanelMouseDown = props.onPanelMouseDown,
  27. direction = props.direction,
  28. value = props.value,
  29. onSelect = props.onSelect,
  30. isInvalid = props.isInvalid,
  31. defaultOpenValue = props.defaultOpenValue,
  32. onOk = props.onOk,
  33. onSubmit = props.onSubmit;
  34. var _React$useContext = React.useContext(PickerContext),
  35. prefixCls = _React$useContext.prefixCls;
  36. var panelPrefixCls = "".concat(prefixCls, "-panel");
  37. var rtl = direction === 'rtl';
  38. // ========================= Refs =========================
  39. var arrowRef = React.useRef(null);
  40. var wrapperRef = React.useRef(null);
  41. // ======================== Offset ========================
  42. var _React$useState = React.useState(0),
  43. _React$useState2 = _slicedToArray(_React$useState, 2),
  44. containerWidth = _React$useState2[0],
  45. setContainerWidth = _React$useState2[1];
  46. var _React$useState3 = React.useState(0),
  47. _React$useState4 = _slicedToArray(_React$useState3, 2),
  48. containerOffset = _React$useState4[0],
  49. setContainerOffset = _React$useState4[1];
  50. var _React$useState5 = React.useState(0),
  51. _React$useState6 = _slicedToArray(_React$useState5, 2),
  52. arrowOffset = _React$useState6[0],
  53. setArrowOffset = _React$useState6[1];
  54. var onResize = function onResize(info) {
  55. if (info.width) {
  56. setContainerWidth(info.width);
  57. }
  58. };
  59. var _activeInfo = _slicedToArray(activeInfo, 3),
  60. activeInputLeft = _activeInfo[0],
  61. activeInputRight = _activeInfo[1],
  62. selectorWidth = _activeInfo[2];
  63. var _React$useState7 = React.useState(0),
  64. _React$useState8 = _slicedToArray(_React$useState7, 2),
  65. retryTimes = _React$useState8[0],
  66. setRetryTimes = _React$useState8[1];
  67. React.useEffect(function () {
  68. setRetryTimes(10);
  69. }, [activeInputLeft]);
  70. React.useEffect(function () {
  71. // `activeOffset` is always align with the active input element
  72. // So we need only check container contains the `activeOffset`
  73. if (range && wrapperRef.current) {
  74. var _arrowRef$current;
  75. // Offset in case container has border radius
  76. var arrowWidth = ((_arrowRef$current = arrowRef.current) === null || _arrowRef$current === void 0 ? void 0 : _arrowRef$current.offsetWidth) || 0;
  77. // Arrow Offset
  78. var wrapperRect = wrapperRef.current.getBoundingClientRect();
  79. if (!wrapperRect.height || wrapperRect.right < 0) {
  80. setRetryTimes(function (times) {
  81. return Math.max(0, times - 1);
  82. });
  83. return;
  84. }
  85. var nextArrowOffset = (rtl ? activeInputRight - arrowWidth : activeInputLeft) - wrapperRect.left;
  86. setArrowOffset(nextArrowOffset);
  87. // Container Offset
  88. if (containerWidth && containerWidth < selectorWidth) {
  89. var offset = rtl ? wrapperRect.right - (activeInputRight - arrowWidth + containerWidth) : activeInputLeft + arrowWidth - wrapperRect.left - containerWidth;
  90. var safeOffset = Math.max(0, offset);
  91. setContainerOffset(safeOffset);
  92. } else {
  93. setContainerOffset(0);
  94. }
  95. }
  96. }, [retryTimes, rtl, containerWidth, activeInputLeft, activeInputRight, selectorWidth, range]);
  97. // ======================== Custom ========================
  98. function filterEmpty(list) {
  99. return list.filter(function (item) {
  100. return item;
  101. });
  102. }
  103. var valueList = React.useMemo(function () {
  104. return filterEmpty(toArray(value));
  105. }, [value]);
  106. var isTimePickerEmptyValue = picker === 'time' && !valueList.length;
  107. var footerSubmitValue = React.useMemo(function () {
  108. if (isTimePickerEmptyValue) {
  109. return filterEmpty([defaultOpenValue]);
  110. }
  111. return valueList;
  112. }, [isTimePickerEmptyValue, valueList, defaultOpenValue]);
  113. var popupPanelValue = isTimePickerEmptyValue ? defaultOpenValue : valueList;
  114. var disableSubmit = React.useMemo(function () {
  115. // Empty is invalid
  116. if (!footerSubmitValue.length) {
  117. return true;
  118. }
  119. return footerSubmitValue.some(function (val) {
  120. return isInvalid(val);
  121. });
  122. }, [footerSubmitValue, isInvalid]);
  123. var onFooterSubmit = function onFooterSubmit() {
  124. // For TimePicker, we will additional trigger the value update
  125. if (isTimePickerEmptyValue) {
  126. onSelect(defaultOpenValue);
  127. }
  128. onOk();
  129. onSubmit();
  130. };
  131. var mergedNodes = /*#__PURE__*/React.createElement("div", {
  132. className: "".concat(prefixCls, "-panel-layout")
  133. }, /*#__PURE__*/React.createElement(PresetPanel, {
  134. prefixCls: prefixCls,
  135. presets: presets,
  136. onClick: onPresetSubmit,
  137. onHover: onPresetHover
  138. }), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(PopupPanel, _extends({}, props, {
  139. value: popupPanelValue
  140. })), /*#__PURE__*/React.createElement(Footer, _extends({}, props, {
  141. showNow: multiple ? false : showNow,
  142. invalid: disableSubmit,
  143. onSubmit: onFooterSubmit
  144. }))));
  145. if (panelRender) {
  146. mergedNodes = panelRender(mergedNodes);
  147. }
  148. // ======================== Render ========================
  149. var containerPrefixCls = "".concat(panelPrefixCls, "-container");
  150. var marginLeft = 'marginLeft';
  151. var marginRight = 'marginRight';
  152. // Container
  153. var renderNode = /*#__PURE__*/React.createElement("div", {
  154. onMouseDown: onPanelMouseDown,
  155. tabIndex: -1,
  156. className: classNames(containerPrefixCls, // Used for Today Button style, safe to remove if no need
  157. "".concat(prefixCls, "-").concat(internalMode, "-panel-container")),
  158. style: _defineProperty(_defineProperty({}, rtl ? marginRight : marginLeft, containerOffset), rtl ? marginLeft : marginRight, 'auto')
  159. // Still wish not to lose focus on mouse down
  160. // onMouseDown={(e) => {
  161. // // e.preventDefault();
  162. // }}
  163. ,
  164. onFocus: onFocus,
  165. onBlur: onBlur
  166. }, mergedNodes);
  167. if (range) {
  168. renderNode = /*#__PURE__*/React.createElement("div", {
  169. onMouseDown: onPanelMouseDown,
  170. ref: wrapperRef,
  171. className: classNames("".concat(prefixCls, "-range-wrapper"), "".concat(prefixCls, "-").concat(picker, "-range-wrapper"))
  172. }, /*#__PURE__*/React.createElement("div", {
  173. ref: arrowRef,
  174. className: "".concat(prefixCls, "-range-arrow"),
  175. style: {
  176. left: arrowOffset
  177. }
  178. }), /*#__PURE__*/React.createElement(ResizeObserver, {
  179. onResize: onResize
  180. }, renderNode));
  181. }
  182. return renderNode;
  183. }