index.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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 _KeyCode = _interopRequireDefault(require("../../_util/KeyCode"));
  10. var _MultipleSelector = _interopRequireDefault(require("./MultipleSelector"));
  11. var _SingleSelector = _interopRequireDefault(require("./SingleSelector"));
  12. var _keyUtil = require("../utils/keyUtil");
  13. var _useLock = _interopRequireDefault(require("../hooks/useLock"));
  14. var _createRef = _interopRequireDefault(require("../../_util/createRef"));
  15. var _vueTypes = _interopRequireDefault(require("../../_util/vue-types"));
  16. /**
  17. * Cursor rule:
  18. * 1. Only `showSearch` enabled
  19. * 2. Only `open` is `true`
  20. * 3. When typing, set `open` to `true` which hit rule of 2
  21. *
  22. * Accessibility:
  23. * - https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
  24. */
  25. const Selector = (0, _vue.defineComponent)({
  26. name: 'Selector',
  27. inheritAttrs: false,
  28. props: {
  29. id: String,
  30. prefixCls: String,
  31. showSearch: {
  32. type: Boolean,
  33. default: undefined
  34. },
  35. open: {
  36. type: Boolean,
  37. default: undefined
  38. },
  39. /** Display in the Selector value, it's not same as `value` prop */
  40. values: _vueTypes.default.array,
  41. multiple: {
  42. type: Boolean,
  43. default: undefined
  44. },
  45. mode: String,
  46. searchValue: String,
  47. activeValue: String,
  48. inputElement: _vueTypes.default.any,
  49. autofocus: {
  50. type: Boolean,
  51. default: undefined
  52. },
  53. activeDescendantId: String,
  54. tabindex: _vueTypes.default.oneOfType([_vueTypes.default.number, _vueTypes.default.string]),
  55. disabled: {
  56. type: Boolean,
  57. default: undefined
  58. },
  59. placeholder: _vueTypes.default.any,
  60. removeIcon: _vueTypes.default.any,
  61. // Tags
  62. maxTagCount: _vueTypes.default.oneOfType([_vueTypes.default.number, _vueTypes.default.string]),
  63. maxTagTextLength: Number,
  64. maxTagPlaceholder: _vueTypes.default.any,
  65. tagRender: Function,
  66. optionLabelRender: Function,
  67. /** Check if `tokenSeparators` contains `\n` or `\r\n` */
  68. tokenWithEnter: {
  69. type: Boolean,
  70. default: undefined
  71. },
  72. // Motion
  73. choiceTransitionName: String,
  74. onToggleOpen: {
  75. type: Function
  76. },
  77. /** `onSearch` returns go next step boolean to check if need do toggle open */
  78. onSearch: Function,
  79. onSearchSubmit: Function,
  80. onRemove: Function,
  81. onInputKeyDown: {
  82. type: Function
  83. },
  84. /**
  85. * @private get real dom for trigger align.
  86. * This may be removed after React provides replacement of `findDOMNode`
  87. */
  88. domRef: Function
  89. },
  90. setup(props, _ref) {
  91. let {
  92. expose
  93. } = _ref;
  94. const inputRef = (0, _createRef.default)();
  95. const compositionStatus = (0, _vue.ref)(false);
  96. // ====================== Input ======================
  97. const [getInputMouseDown, setInputMouseDown] = (0, _useLock.default)(0);
  98. const onInternalInputKeyDown = event => {
  99. const {
  100. which
  101. } = event;
  102. if (which === _KeyCode.default.UP || which === _KeyCode.default.DOWN) {
  103. event.preventDefault();
  104. }
  105. if (props.onInputKeyDown) {
  106. props.onInputKeyDown(event);
  107. }
  108. if (which === _KeyCode.default.ENTER && props.mode === 'tags' && !compositionStatus.value && !props.open) {
  109. // When menu isn't open, OptionList won't trigger a value change
  110. // So when enter is pressed, the tag's input value should be emitted here to let selector know
  111. props.onSearchSubmit(event.target.value);
  112. }
  113. if ((0, _keyUtil.isValidateOpenKey)(which)) {
  114. props.onToggleOpen(true);
  115. }
  116. };
  117. /**
  118. * We can not use `findDOMNode` sine it will get warning,
  119. * have to use timer to check if is input element.
  120. */
  121. const onInternalInputMouseDown = () => {
  122. setInputMouseDown(true);
  123. };
  124. // When paste come, ignore next onChange
  125. let pastedText = null;
  126. const triggerOnSearch = value => {
  127. if (props.onSearch(value, true, compositionStatus.value) !== false) {
  128. props.onToggleOpen(true);
  129. }
  130. };
  131. const onInputCompositionStart = () => {
  132. compositionStatus.value = true;
  133. };
  134. const onInputCompositionEnd = e => {
  135. compositionStatus.value = false;
  136. // Trigger search again to support `tokenSeparators` with typewriting
  137. if (props.mode !== 'combobox') {
  138. triggerOnSearch(e.target.value);
  139. }
  140. };
  141. const onInputChange = event => {
  142. let {
  143. target: {
  144. value
  145. }
  146. } = event;
  147. // Pasted text should replace back to origin content
  148. if (props.tokenWithEnter && pastedText && /[\r\n]/.test(pastedText)) {
  149. // CRLF will be treated as a single space for input element
  150. const replacedText = pastedText.replace(/[\r\n]+$/, '').replace(/\r\n/g, ' ').replace(/[\r\n]/g, ' ');
  151. value = value.replace(replacedText, pastedText);
  152. }
  153. pastedText = null;
  154. triggerOnSearch(value);
  155. };
  156. const onInputPaste = e => {
  157. const {
  158. clipboardData
  159. } = e;
  160. const value = clipboardData.getData('text');
  161. pastedText = value;
  162. };
  163. const onClick = _ref2 => {
  164. let {
  165. target
  166. } = _ref2;
  167. if (target !== inputRef.current) {
  168. // Should focus input if click the selector
  169. const isIE = document.body.style.msTouchAction !== undefined;
  170. if (isIE) {
  171. setTimeout(() => {
  172. inputRef.current.focus();
  173. });
  174. } else {
  175. inputRef.current.focus();
  176. }
  177. }
  178. };
  179. const onMousedown = event => {
  180. const inputMouseDown = getInputMouseDown();
  181. if (event.target !== inputRef.current && !inputMouseDown) {
  182. event.preventDefault();
  183. }
  184. if (props.mode !== 'combobox' && (!props.showSearch || !inputMouseDown) || !props.open) {
  185. if (props.open) {
  186. props.onSearch('', true, false);
  187. }
  188. props.onToggleOpen();
  189. }
  190. };
  191. expose({
  192. focus: () => {
  193. inputRef.current.focus();
  194. },
  195. blur: () => {
  196. inputRef.current.blur();
  197. }
  198. });
  199. return () => {
  200. const {
  201. prefixCls,
  202. domRef,
  203. mode
  204. } = props;
  205. const sharedProps = {
  206. inputRef,
  207. onInputKeyDown: onInternalInputKeyDown,
  208. onInputMouseDown: onInternalInputMouseDown,
  209. onInputChange,
  210. onInputPaste,
  211. compositionStatus: compositionStatus.value,
  212. onInputCompositionStart,
  213. onInputCompositionEnd
  214. };
  215. const selectNode = mode === 'multiple' || mode === 'tags' ? (0, _vue.createVNode)(_MultipleSelector.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), sharedProps), null) : (0, _vue.createVNode)(_SingleSelector.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), sharedProps), null);
  216. return (0, _vue.createVNode)("div", {
  217. "ref": domRef,
  218. "class": `${prefixCls}-selector`,
  219. "onClick": onClick,
  220. "onMousedown": onMousedown
  221. }, [selectNode]);
  222. };
  223. }
  224. });
  225. var _default = exports.default = Selector;