Picker.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = void 0;
  7. var _vue = require("vue");
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  10. var _PickerPanel = _interopRequireDefault(require("./PickerPanel"));
  11. var _PickerTrigger = _interopRequireDefault(require("./PickerTrigger"));
  12. var _PresetPanel = _interopRequireDefault(require("./PresetPanel"));
  13. var _dateUtil = require("./utils/dateUtil");
  14. var _miscUtil = _interopRequireWildcard(require("./utils/miscUtil"));
  15. var _PanelContext = require("./PanelContext");
  16. var _uiUtil = require("./utils/uiUtil");
  17. var _usePickerInput = _interopRequireDefault(require("./hooks/usePickerInput"));
  18. var _useTextValueMapping = _interopRequireDefault(require("./hooks/useTextValueMapping"));
  19. var _useValueTexts = _interopRequireDefault(require("./hooks/useValueTexts"));
  20. var _useHoverValue = _interopRequireDefault(require("./hooks/useHoverValue"));
  21. var _usePresets = _interopRequireDefault(require("./hooks/usePresets"));
  22. var _useMergedState = _interopRequireDefault(require("../_util/hooks/useMergedState"));
  23. var _warning = require("../vc-util/warning");
  24. var _classNames = _interopRequireDefault(require("../_util/classNames"));
  25. var _warnUtil = require("./utils/warnUtil");
  26. function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
  27. function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
  28. /**
  29. * Removed:
  30. * - getCalendarContainer: use `getPopupContainer` instead
  31. * - onOk
  32. *
  33. * New Feature:
  34. * - picker
  35. * - allowEmpty
  36. * - selectable
  37. *
  38. * Tips: Should add faq about `datetime` mode with `defaultValue`
  39. */
  40. function Picker() {
  41. return (0, _vue.defineComponent)({
  42. name: 'Picker',
  43. inheritAttrs: false,
  44. props: ['prefixCls', 'id', 'tabindex', 'dropdownClassName', 'dropdownAlign', 'popupStyle', 'transitionName', 'generateConfig', 'locale', 'inputReadOnly', 'allowClear', 'autofocus', 'showTime', 'showNow', 'showHour', 'showMinute', 'showSecond', 'picker', 'format', 'use12Hours', 'value', 'defaultValue', 'open', 'defaultOpen', 'defaultOpenValue', 'suffixIcon', 'presets', 'clearIcon', 'disabled', 'disabledDate', 'placeholder', 'getPopupContainer', 'panelRender', 'inputRender', 'onChange', 'onOpenChange', 'onPanelChange', 'onFocus', 'onBlur', 'onMousedown', 'onMouseup', 'onMouseenter', 'onMouseleave', 'onContextmenu', 'onClick', 'onKeydown', 'onSelect', 'direction', 'autocomplete', 'showToday', 'renderExtraFooter', 'dateRender', 'minuteStep', 'hourStep', 'secondStep', 'hideDisabledOptions'],
  45. setup(props, _ref) {
  46. let {
  47. attrs,
  48. expose
  49. } = _ref;
  50. const inputRef = (0, _vue.ref)(null);
  51. const presets = (0, _vue.computed)(() => props.presets);
  52. const presetList = (0, _usePresets.default)(presets);
  53. const picker = (0, _vue.computed)(() => {
  54. var _a;
  55. return (_a = props.picker) !== null && _a !== void 0 ? _a : 'date';
  56. });
  57. const needConfirmButton = (0, _vue.computed)(() => picker.value === 'date' && !!props.showTime || picker.value === 'time');
  58. // ============================ Warning ============================
  59. if (process.env.NODE_ENV !== 'production') {
  60. (0, _warnUtil.legacyPropsWarning)(props);
  61. }
  62. // ============================= State =============================
  63. const formatList = (0, _vue.computed)(() => (0, _miscUtil.toArray)((0, _uiUtil.getDefaultFormat)(props.format, picker.value, props.showTime, props.use12Hours)));
  64. // Panel ref
  65. const panelDivRef = (0, _vue.ref)(null);
  66. const inputDivRef = (0, _vue.ref)(null);
  67. const containerRef = (0, _vue.ref)(null);
  68. // Real value
  69. const [mergedValue, setInnerValue] = (0, _useMergedState.default)(null, {
  70. value: (0, _vue.toRef)(props, 'value'),
  71. defaultValue: props.defaultValue
  72. });
  73. const selectedValue = (0, _vue.ref)(mergedValue.value);
  74. const setSelectedValue = val => {
  75. selectedValue.value = val;
  76. };
  77. // Operation ref
  78. const operationRef = (0, _vue.ref)(null);
  79. // Open
  80. const [mergedOpen, triggerInnerOpen] = (0, _useMergedState.default)(false, {
  81. value: (0, _vue.toRef)(props, 'open'),
  82. defaultValue: props.defaultOpen,
  83. postState: postOpen => props.disabled ? false : postOpen,
  84. onChange: newOpen => {
  85. if (props.onOpenChange) {
  86. props.onOpenChange(newOpen);
  87. }
  88. if (!newOpen && operationRef.value && operationRef.value.onClose) {
  89. operationRef.value.onClose();
  90. }
  91. }
  92. });
  93. // ============================= Text ==============================
  94. const [valueTexts, firstValueText] = (0, _useValueTexts.default)(selectedValue, {
  95. formatList,
  96. generateConfig: (0, _vue.toRef)(props, 'generateConfig'),
  97. locale: (0, _vue.toRef)(props, 'locale')
  98. });
  99. const [text, triggerTextChange, resetText] = (0, _useTextValueMapping.default)({
  100. valueTexts,
  101. onTextChange: newText => {
  102. const inputDate = (0, _dateUtil.parseValue)(newText, {
  103. locale: props.locale,
  104. formatList: formatList.value,
  105. generateConfig: props.generateConfig
  106. });
  107. if (inputDate && (!props.disabledDate || !props.disabledDate(inputDate))) {
  108. setSelectedValue(inputDate);
  109. }
  110. }
  111. });
  112. // ============================ Trigger ============================
  113. const triggerChange = newValue => {
  114. const {
  115. onChange,
  116. generateConfig,
  117. locale
  118. } = props;
  119. setSelectedValue(newValue);
  120. setInnerValue(newValue);
  121. if (onChange && !(0, _dateUtil.isEqual)(generateConfig, mergedValue.value, newValue)) {
  122. onChange(newValue, newValue ? (0, _dateUtil.formatValue)(newValue, {
  123. generateConfig,
  124. locale,
  125. format: formatList.value[0]
  126. }) : '');
  127. }
  128. };
  129. const triggerOpen = newOpen => {
  130. if (props.disabled && newOpen) {
  131. return;
  132. }
  133. triggerInnerOpen(newOpen);
  134. };
  135. const forwardKeydown = e => {
  136. if (mergedOpen.value && operationRef.value && operationRef.value.onKeydown) {
  137. // Let popup panel handle keyboard
  138. return operationRef.value.onKeydown(e);
  139. }
  140. /* istanbul ignore next */
  141. /* eslint-disable no-lone-blocks */
  142. {
  143. (0, _warning.warning)(false, 'Picker not correct forward Keydown operation. Please help to fire issue about this.');
  144. return false;
  145. }
  146. };
  147. const onInternalMouseup = function () {
  148. if (props.onMouseup) {
  149. props.onMouseup(...arguments);
  150. }
  151. if (inputRef.value) {
  152. inputRef.value.focus();
  153. triggerOpen(true);
  154. }
  155. };
  156. // ============================= Input =============================
  157. const [inputProps, {
  158. focused,
  159. typing
  160. }] = (0, _usePickerInput.default)({
  161. blurToCancel: needConfirmButton,
  162. open: mergedOpen,
  163. value: text,
  164. triggerOpen,
  165. forwardKeydown,
  166. isClickOutside: target => !(0, _uiUtil.elementsContains)([panelDivRef.value, inputDivRef.value, containerRef.value], target),
  167. onSubmit: () => {
  168. if (
  169. // When user typing disabledDate with keyboard and enter, this value will be empty
  170. !selectedValue.value ||
  171. // Normal disabled check
  172. props.disabledDate && props.disabledDate(selectedValue.value)) {
  173. return false;
  174. }
  175. triggerChange(selectedValue.value);
  176. triggerOpen(false);
  177. resetText();
  178. return true;
  179. },
  180. onCancel: () => {
  181. triggerOpen(false);
  182. setSelectedValue(mergedValue.value);
  183. resetText();
  184. },
  185. onKeydown: (e, preventDefault) => {
  186. var _a;
  187. (_a = props.onKeydown) === null || _a === void 0 ? void 0 : _a.call(props, e, preventDefault);
  188. },
  189. onFocus: e => {
  190. var _a;
  191. (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
  192. },
  193. onBlur: e => {
  194. var _a;
  195. (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
  196. }
  197. });
  198. // ============================= Sync ==============================
  199. // Close should sync back with text value
  200. (0, _vue.watch)([mergedOpen, valueTexts], () => {
  201. if (!mergedOpen.value) {
  202. setSelectedValue(mergedValue.value);
  203. if (!valueTexts.value.length || valueTexts.value[0] === '') {
  204. triggerTextChange('');
  205. } else if (firstValueText.value !== text.value) {
  206. resetText();
  207. }
  208. }
  209. });
  210. // Change picker should sync back with text value
  211. (0, _vue.watch)(picker, () => {
  212. if (!mergedOpen.value) {
  213. resetText();
  214. }
  215. });
  216. // Sync innerValue with control mode
  217. (0, _vue.watch)(mergedValue, () => {
  218. // Sync select value
  219. setSelectedValue(mergedValue.value);
  220. });
  221. const [hoverValue, onEnter, onLeave] = (0, _useHoverValue.default)(text, {
  222. formatList,
  223. generateConfig: (0, _vue.toRef)(props, 'generateConfig'),
  224. locale: (0, _vue.toRef)(props, 'locale')
  225. });
  226. const onContextSelect = (date, type) => {
  227. if (type === 'submit' || type !== 'key' && !needConfirmButton.value) {
  228. // triggerChange will also update selected values
  229. triggerChange(date);
  230. triggerOpen(false);
  231. }
  232. };
  233. (0, _PanelContext.useProvidePanel)({
  234. operationRef,
  235. hideHeader: (0, _vue.computed)(() => picker.value === 'time'),
  236. onSelect: onContextSelect,
  237. open: mergedOpen,
  238. defaultOpenValue: (0, _vue.toRef)(props, 'defaultOpenValue'),
  239. onDateMouseenter: onEnter,
  240. onDateMouseleave: onLeave
  241. });
  242. expose({
  243. focus: () => {
  244. if (inputRef.value) {
  245. inputRef.value.focus();
  246. }
  247. },
  248. blur: () => {
  249. if (inputRef.value) {
  250. inputRef.value.blur();
  251. }
  252. }
  253. });
  254. return () => {
  255. const {
  256. prefixCls = 'rc-picker',
  257. id,
  258. tabindex,
  259. dropdownClassName,
  260. dropdownAlign,
  261. popupStyle,
  262. transitionName,
  263. generateConfig,
  264. locale,
  265. inputReadOnly,
  266. allowClear,
  267. autofocus,
  268. picker = 'date',
  269. defaultOpenValue,
  270. suffixIcon,
  271. clearIcon,
  272. disabled,
  273. placeholder,
  274. getPopupContainer,
  275. panelRender,
  276. onMousedown,
  277. onMouseenter,
  278. onMouseleave,
  279. onContextmenu,
  280. onClick,
  281. onSelect,
  282. direction,
  283. autocomplete = 'off'
  284. } = props;
  285. // ============================= Panel =============================
  286. const panelProps = (0, _extends2.default)((0, _extends2.default)((0, _extends2.default)({}, props), attrs), {
  287. class: (0, _classNames.default)({
  288. [`${prefixCls}-panel-focused`]: !typing.value
  289. }),
  290. style: undefined,
  291. pickerValue: undefined,
  292. onPickerValueChange: undefined,
  293. onChange: null
  294. });
  295. let panelNode = (0, _vue.createVNode)("div", {
  296. "class": `${prefixCls}-panel-layout`
  297. }, [(0, _vue.createVNode)(_PresetPanel.default, {
  298. "prefixCls": prefixCls,
  299. "presets": presetList.value,
  300. "onClick": nextValue => {
  301. triggerChange(nextValue);
  302. triggerOpen(false);
  303. }
  304. }, null), (0, _vue.createVNode)(_PickerPanel.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, panelProps), {}, {
  305. "generateConfig": generateConfig,
  306. "value": selectedValue.value,
  307. "locale": locale,
  308. "tabindex": -1,
  309. "onSelect": date => {
  310. onSelect === null || onSelect === void 0 ? void 0 : onSelect(date);
  311. setSelectedValue(date);
  312. },
  313. "direction": direction,
  314. "onPanelChange": (viewDate, mode) => {
  315. const {
  316. onPanelChange
  317. } = props;
  318. onLeave(true);
  319. onPanelChange === null || onPanelChange === void 0 ? void 0 : onPanelChange(viewDate, mode);
  320. }
  321. }), null)]);
  322. if (panelRender) {
  323. panelNode = panelRender(panelNode);
  324. }
  325. const panel = (0, _vue.createVNode)("div", {
  326. "class": `${prefixCls}-panel-container`,
  327. "ref": panelDivRef,
  328. "onMousedown": e => {
  329. e.preventDefault();
  330. }
  331. }, [panelNode]);
  332. let suffixNode;
  333. if (suffixIcon) {
  334. suffixNode = (0, _vue.createVNode)("span", {
  335. "class": `${prefixCls}-suffix`
  336. }, [suffixIcon]);
  337. }
  338. let clearNode;
  339. if (allowClear && mergedValue.value && !disabled) {
  340. clearNode = (0, _vue.createVNode)("span", {
  341. "onMousedown": e => {
  342. e.preventDefault();
  343. e.stopPropagation();
  344. },
  345. "onMouseup": e => {
  346. e.preventDefault();
  347. e.stopPropagation();
  348. triggerChange(null);
  349. triggerOpen(false);
  350. },
  351. "class": `${prefixCls}-clear`,
  352. "role": "button"
  353. }, [clearIcon || (0, _vue.createVNode)("span", {
  354. "class": `${prefixCls}-clear-btn`
  355. }, null)]);
  356. }
  357. const mergedInputProps = (0, _extends2.default)((0, _extends2.default)((0, _extends2.default)((0, _extends2.default)({
  358. id,
  359. tabindex,
  360. disabled,
  361. readonly: inputReadOnly || typeof formatList.value[0] === 'function' || !typing.value,
  362. value: hoverValue.value || text.value,
  363. onInput: e => {
  364. triggerTextChange(e.target.value);
  365. },
  366. autofocus,
  367. placeholder,
  368. ref: inputRef,
  369. title: text.value
  370. }, inputProps.value), {
  371. size: (0, _uiUtil.getInputSize)(picker, formatList.value[0], generateConfig)
  372. }), (0, _miscUtil.default)(props)), {
  373. autocomplete
  374. });
  375. const inputNode = props.inputRender ? props.inputRender(mergedInputProps) : (0, _vue.createVNode)("input", mergedInputProps, null);
  376. // ============================ Warning ============================
  377. if (process.env.NODE_ENV !== 'production') {
  378. (0, _warning.warning)(!defaultOpenValue, '`defaultOpenValue` may confuse user for the current value status. Please use `defaultValue` instead.');
  379. }
  380. // ============================ Return =============================
  381. const popupPlacement = direction === 'rtl' ? 'bottomRight' : 'bottomLeft';
  382. return (0, _vue.createVNode)("div", {
  383. "ref": containerRef,
  384. "class": (0, _classNames.default)(prefixCls, attrs.class, {
  385. [`${prefixCls}-disabled`]: disabled,
  386. [`${prefixCls}-focused`]: focused.value,
  387. [`${prefixCls}-rtl`]: direction === 'rtl'
  388. }),
  389. "style": attrs.style,
  390. "onMousedown": onMousedown,
  391. "onMouseup": onInternalMouseup,
  392. "onMouseenter": onMouseenter,
  393. "onMouseleave": onMouseleave,
  394. "onContextmenu": onContextmenu,
  395. "onClick": onClick
  396. }, [(0, _vue.createVNode)("div", {
  397. "class": (0, _classNames.default)(`${prefixCls}-input`, {
  398. [`${prefixCls}-input-placeholder`]: !!hoverValue.value
  399. }),
  400. "ref": inputDivRef
  401. }, [inputNode, suffixNode, clearNode]), (0, _vue.createVNode)(_PickerTrigger.default, {
  402. "visible": mergedOpen.value,
  403. "popupStyle": popupStyle,
  404. "prefixCls": prefixCls,
  405. "dropdownClassName": dropdownClassName,
  406. "dropdownAlign": dropdownAlign,
  407. "getPopupContainer": getPopupContainer,
  408. "transitionName": transitionName,
  409. "popupPlacement": popupPlacement,
  410. "direction": direction
  411. }, {
  412. default: () => [(0, _vue.createVNode)("div", {
  413. "style": {
  414. pointerEvents: 'none',
  415. position: 'absolute',
  416. top: 0,
  417. bottom: 0,
  418. left: 0,
  419. right: 0
  420. }
  421. }, null)],
  422. popupElement: () => panel
  423. })]);
  424. };
  425. }
  426. });
  427. }
  428. var _default = exports.default = Picker();