BaseSelect.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import { resolveDirective as _resolveDirective, createTextVNode as _createTextVNode, createVNode as _createVNode } from "vue";
  4. var __rest = this && this.__rest || function (s, e) {
  5. var t = {};
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  7. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  8. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  9. }
  10. return t;
  11. };
  12. import { getSeparatedContent } from './utils/valueUtil';
  13. import SelectTrigger from './SelectTrigger';
  14. import Selector from './Selector';
  15. import useSelectTriggerControl from './hooks/useSelectTriggerControl';
  16. import useDelayReset from './hooks/useDelayReset';
  17. import TransBtn from './TransBtn';
  18. import useLock from './hooks/useLock';
  19. import { useProvideBaseSelectProps } from './hooks/useBaseProps';
  20. import { computed, defineComponent, onBeforeUnmount, onMounted, provide, shallowRef, toRefs, watch, watchEffect, ref } from 'vue';
  21. import PropTypes from '../_util/vue-types';
  22. import { initDefaultProps, isValidElement } from '../_util/props-util';
  23. import isMobile from '../vc-util/isMobile';
  24. import KeyCode from '../_util/KeyCode';
  25. import { toReactive } from '../_util/toReactive';
  26. import classNames from '../_util/classNames';
  27. import createRef from '../_util/createRef';
  28. import useInjectLegacySelectContext from '../vc-tree-select/LegacyContext';
  29. import { cloneElement } from '../_util/vnode';
  30. const DEFAULT_OMIT_PROPS = ['value', 'onChange', 'removeIcon', 'placeholder', 'autofocus', 'maxTagCount', 'maxTagTextLength', 'maxTagPlaceholder', 'choiceTransitionName', 'onInputKeyDown', 'onPopupScroll', 'tabindex', 'OptionList', 'notFoundContent'];
  31. const baseSelectPrivateProps = () => {
  32. return {
  33. prefixCls: String,
  34. id: String,
  35. omitDomProps: Array,
  36. // >>> Value
  37. displayValues: Array,
  38. onDisplayValuesChange: Function,
  39. // >>> Active
  40. /** Current dropdown list active item string value */
  41. activeValue: String,
  42. /** Link search input with target element */
  43. activeDescendantId: String,
  44. onActiveValueChange: Function,
  45. // >>> Search
  46. searchValue: String,
  47. /** Trigger onSearch, return false to prevent trigger open event */
  48. onSearch: Function,
  49. /** Trigger when search text match the `tokenSeparators`. Will provide split content */
  50. onSearchSplit: Function,
  51. maxLength: Number,
  52. OptionList: PropTypes.any,
  53. /** Tell if provided `options` is empty */
  54. emptyOptions: Boolean
  55. };
  56. };
  57. export const baseSelectPropsWithoutPrivate = () => {
  58. return {
  59. showSearch: {
  60. type: Boolean,
  61. default: undefined
  62. },
  63. tagRender: {
  64. type: Function
  65. },
  66. optionLabelRender: {
  67. type: Function
  68. },
  69. direction: {
  70. type: String
  71. },
  72. // MISC
  73. tabindex: Number,
  74. autofocus: Boolean,
  75. notFoundContent: PropTypes.any,
  76. placeholder: PropTypes.any,
  77. onClear: Function,
  78. choiceTransitionName: String,
  79. // >>> Mode
  80. mode: String,
  81. // >>> Status
  82. disabled: {
  83. type: Boolean,
  84. default: undefined
  85. },
  86. loading: {
  87. type: Boolean,
  88. default: undefined
  89. },
  90. // >>> Open
  91. open: {
  92. type: Boolean,
  93. default: undefined
  94. },
  95. defaultOpen: {
  96. type: Boolean,
  97. default: undefined
  98. },
  99. onDropdownVisibleChange: {
  100. type: Function
  101. },
  102. // >>> Customize Input
  103. /** @private Internal usage. Do not use in your production. */
  104. getInputElement: {
  105. type: Function
  106. },
  107. /** @private Internal usage. Do not use in your production. */
  108. getRawInputElement: {
  109. type: Function
  110. },
  111. // >>> Selector
  112. maxTagTextLength: Number,
  113. maxTagCount: {
  114. type: [String, Number]
  115. },
  116. maxTagPlaceholder: PropTypes.any,
  117. // >>> Search
  118. tokenSeparators: {
  119. type: Array
  120. },
  121. // >>> Icons
  122. allowClear: {
  123. type: Boolean,
  124. default: undefined
  125. },
  126. showArrow: {
  127. type: Boolean,
  128. default: undefined
  129. },
  130. inputIcon: PropTypes.any,
  131. /** Clear all icon */
  132. clearIcon: PropTypes.any,
  133. /** Selector remove icon */
  134. removeIcon: PropTypes.any,
  135. // >>> Dropdown
  136. animation: String,
  137. transitionName: String,
  138. dropdownStyle: {
  139. type: Object
  140. },
  141. dropdownClassName: String,
  142. dropdownMatchSelectWidth: {
  143. type: [Boolean, Number],
  144. default: undefined
  145. },
  146. dropdownRender: {
  147. type: Function
  148. },
  149. dropdownAlign: Object,
  150. placement: {
  151. type: String
  152. },
  153. getPopupContainer: {
  154. type: Function
  155. },
  156. // >>> Focus
  157. showAction: {
  158. type: Array
  159. },
  160. onBlur: {
  161. type: Function
  162. },
  163. onFocus: {
  164. type: Function
  165. },
  166. // >>> Rest Events
  167. onKeyup: Function,
  168. onKeydown: Function,
  169. onMousedown: Function,
  170. onPopupScroll: Function,
  171. onInputKeyDown: Function,
  172. onMouseenter: Function,
  173. onMouseleave: Function,
  174. onClick: Function
  175. };
  176. };
  177. const baseSelectProps = () => {
  178. return _extends(_extends({}, baseSelectPrivateProps()), baseSelectPropsWithoutPrivate());
  179. };
  180. export function isMultiple(mode) {
  181. return mode === 'tags' || mode === 'multiple';
  182. }
  183. export default defineComponent({
  184. compatConfig: {
  185. MODE: 3
  186. },
  187. name: 'BaseSelect',
  188. inheritAttrs: false,
  189. props: initDefaultProps(baseSelectProps(), {
  190. showAction: [],
  191. notFoundContent: 'Not Found'
  192. }),
  193. setup(props, _ref) {
  194. let {
  195. attrs,
  196. expose,
  197. slots
  198. } = _ref;
  199. const multiple = computed(() => isMultiple(props.mode));
  200. const mergedShowSearch = computed(() => props.showSearch !== undefined ? props.showSearch : multiple.value || props.mode === 'combobox');
  201. const mobile = shallowRef(false);
  202. onMounted(() => {
  203. mobile.value = isMobile();
  204. });
  205. const legacyTreeSelectContext = useInjectLegacySelectContext();
  206. // ============================== Refs ==============================
  207. const containerRef = shallowRef(null);
  208. const selectorDomRef = createRef();
  209. const triggerRef = shallowRef(null);
  210. const selectorRef = shallowRef(null);
  211. const listRef = shallowRef(null);
  212. const blurRef = ref(false);
  213. /** Used for component focused management */
  214. const [mockFocused, setMockFocused, cancelSetMockFocused] = useDelayReset();
  215. const focus = () => {
  216. var _a;
  217. (_a = selectorRef.value) === null || _a === void 0 ? void 0 : _a.focus();
  218. };
  219. const blur = () => {
  220. var _a;
  221. (_a = selectorRef.value) === null || _a === void 0 ? void 0 : _a.blur();
  222. };
  223. expose({
  224. focus,
  225. blur,
  226. scrollTo: arg => {
  227. var _a;
  228. return (_a = listRef.value) === null || _a === void 0 ? void 0 : _a.scrollTo(arg);
  229. }
  230. });
  231. const mergedSearchValue = computed(() => {
  232. var _a;
  233. if (props.mode !== 'combobox') {
  234. return props.searchValue;
  235. }
  236. const val = (_a = props.displayValues[0]) === null || _a === void 0 ? void 0 : _a.value;
  237. return typeof val === 'string' || typeof val === 'number' ? String(val) : '';
  238. });
  239. // ============================== Open ==============================
  240. const initOpen = props.open !== undefined ? props.open : props.defaultOpen;
  241. const innerOpen = shallowRef(initOpen);
  242. const mergedOpen = shallowRef(initOpen);
  243. const setInnerOpen = val => {
  244. innerOpen.value = props.open !== undefined ? props.open : val;
  245. mergedOpen.value = innerOpen.value;
  246. };
  247. watch(() => props.open, () => {
  248. setInnerOpen(props.open);
  249. });
  250. // Not trigger `open` in `combobox` when `notFoundContent` is empty
  251. const emptyListContent = computed(() => !props.notFoundContent && props.emptyOptions);
  252. watchEffect(() => {
  253. mergedOpen.value = innerOpen.value;
  254. if (props.disabled || emptyListContent.value && mergedOpen.value && props.mode === 'combobox') {
  255. mergedOpen.value = false;
  256. }
  257. });
  258. const triggerOpen = computed(() => emptyListContent.value ? false : mergedOpen.value);
  259. const onToggleOpen = newOpen => {
  260. const nextOpen = newOpen !== undefined ? newOpen : !mergedOpen.value;
  261. if (mergedOpen.value !== nextOpen && !props.disabled) {
  262. setInnerOpen(nextOpen);
  263. props.onDropdownVisibleChange && props.onDropdownVisibleChange(nextOpen);
  264. }
  265. };
  266. const tokenWithEnter = computed(() => (props.tokenSeparators || []).some(tokenSeparator => ['\n', '\r\n'].includes(tokenSeparator)));
  267. const onInternalSearch = (searchText, fromTyping, isCompositing) => {
  268. var _a, _b;
  269. let ret = true;
  270. let newSearchText = searchText;
  271. (_a = props.onActiveValueChange) === null || _a === void 0 ? void 0 : _a.call(props, null);
  272. // Check if match the `tokenSeparators`
  273. const patchLabels = isCompositing ? null : getSeparatedContent(searchText, props.tokenSeparators);
  274. // Ignore combobox since it's not split-able
  275. if (props.mode !== 'combobox' && patchLabels) {
  276. newSearchText = '';
  277. (_b = props.onSearchSplit) === null || _b === void 0 ? void 0 : _b.call(props, patchLabels);
  278. // Should close when paste finish
  279. onToggleOpen(false);
  280. // Tell Selector that break next actions
  281. ret = false;
  282. }
  283. if (props.onSearch && mergedSearchValue.value !== newSearchText) {
  284. props.onSearch(newSearchText, {
  285. source: fromTyping ? 'typing' : 'effect'
  286. });
  287. }
  288. return ret;
  289. };
  290. // Only triggered when menu is closed & mode is tags
  291. // If menu is open, OptionList will take charge
  292. // If mode isn't tags, press enter is not meaningful when you can't see any option
  293. const onInternalSearchSubmit = searchText => {
  294. var _a;
  295. // prevent empty tags from appearing when you click the Enter button
  296. if (!searchText || !searchText.trim()) {
  297. return;
  298. }
  299. (_a = props.onSearch) === null || _a === void 0 ? void 0 : _a.call(props, searchText, {
  300. source: 'submit'
  301. });
  302. };
  303. // Close will clean up single mode search text
  304. watch(mergedOpen, () => {
  305. if (!mergedOpen.value && !multiple.value && props.mode !== 'combobox') {
  306. onInternalSearch('', false, false);
  307. }
  308. }, {
  309. immediate: true,
  310. flush: 'post'
  311. });
  312. // ============================ Disabled ============================
  313. // Close dropdown & remove focus state when disabled change
  314. watch(() => props.disabled, () => {
  315. if (innerOpen.value && !!props.disabled) {
  316. setInnerOpen(false);
  317. }
  318. if (props.disabled && !blurRef.value) {
  319. setMockFocused(false);
  320. }
  321. }, {
  322. immediate: true
  323. });
  324. // ============================ Keyboard ============================
  325. /**
  326. * We record input value here to check if can press to clean up by backspace
  327. * - null: Key is not down, this is reset by key up
  328. * - true: Search text is empty when first time backspace down
  329. * - false: Search text is not empty when first time backspace down
  330. */
  331. const [getClearLock, setClearLock] = useLock();
  332. // KeyDown
  333. const onInternalKeyDown = function (event) {
  334. var _a;
  335. const clearLock = getClearLock();
  336. const {
  337. which
  338. } = event;
  339. if (which === KeyCode.ENTER) {
  340. // Do not submit form when type in the input
  341. if (props.mode !== 'combobox') {
  342. event.preventDefault();
  343. }
  344. // We only manage open state here, close logic should handle by list component
  345. if (!mergedOpen.value) {
  346. onToggleOpen(true);
  347. }
  348. }
  349. setClearLock(!!mergedSearchValue.value);
  350. // Remove value by `backspace`
  351. if (which === KeyCode.BACKSPACE && !clearLock && multiple.value && !mergedSearchValue.value && props.displayValues.length) {
  352. const cloneDisplayValues = [...props.displayValues];
  353. let removedDisplayValue = null;
  354. for (let i = cloneDisplayValues.length - 1; i >= 0; i -= 1) {
  355. const current = cloneDisplayValues[i];
  356. if (!current.disabled) {
  357. cloneDisplayValues.splice(i, 1);
  358. removedDisplayValue = current;
  359. break;
  360. }
  361. }
  362. if (removedDisplayValue) {
  363. props.onDisplayValuesChange(cloneDisplayValues, {
  364. type: 'remove',
  365. values: [removedDisplayValue]
  366. });
  367. }
  368. }
  369. for (var _len = arguments.length, rest = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  370. rest[_key - 1] = arguments[_key];
  371. }
  372. if (mergedOpen.value && listRef.value) {
  373. listRef.value.onKeydown(event, ...rest);
  374. }
  375. (_a = props.onKeydown) === null || _a === void 0 ? void 0 : _a.call(props, event, ...rest);
  376. };
  377. // KeyUp
  378. const onInternalKeyUp = function (event) {
  379. for (var _len2 = arguments.length, rest = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  380. rest[_key2 - 1] = arguments[_key2];
  381. }
  382. if (mergedOpen.value && listRef.value) {
  383. listRef.value.onKeyup(event, ...rest);
  384. }
  385. if (props.onKeyup) {
  386. props.onKeyup(event, ...rest);
  387. }
  388. };
  389. // ============================ Selector ============================
  390. const onSelectorRemove = val => {
  391. const newValues = props.displayValues.filter(i => i !== val);
  392. props.onDisplayValuesChange(newValues, {
  393. type: 'remove',
  394. values: [val]
  395. });
  396. };
  397. // ========================== Focus / Blur ==========================
  398. /** Record real focus status */
  399. const focusRef = shallowRef(false);
  400. const onContainerFocus = function () {
  401. setMockFocused(true);
  402. if (!props.disabled) {
  403. if (props.onFocus && !focusRef.value) {
  404. props.onFocus(...arguments);
  405. }
  406. // `showAction` should handle `focus` if set
  407. if (props.showAction && props.showAction.includes('focus')) {
  408. onToggleOpen(true);
  409. }
  410. }
  411. focusRef.value = true;
  412. };
  413. const popupFocused = ref(false);
  414. const onContainerBlur = function () {
  415. if (popupFocused.value) {
  416. return;
  417. }
  418. blurRef.value = true;
  419. setMockFocused(false, () => {
  420. focusRef.value = false;
  421. blurRef.value = false;
  422. onToggleOpen(false);
  423. });
  424. if (props.disabled) {
  425. return;
  426. }
  427. const searchVal = mergedSearchValue.value;
  428. if (searchVal) {
  429. // `tags` mode should move `searchValue` into values
  430. if (props.mode === 'tags') {
  431. props.onSearch(searchVal, {
  432. source: 'submit'
  433. });
  434. } else if (props.mode === 'multiple') {
  435. // `multiple` mode only clean the search value but not trigger event
  436. props.onSearch('', {
  437. source: 'blur'
  438. });
  439. }
  440. }
  441. if (props.onBlur) {
  442. props.onBlur(...arguments);
  443. }
  444. };
  445. const onPopupFocusin = () => {
  446. popupFocused.value = true;
  447. };
  448. const onPopupFocusout = () => {
  449. popupFocused.value = false;
  450. };
  451. provide('VCSelectContainerEvent', {
  452. focus: onContainerFocus,
  453. blur: onContainerBlur
  454. });
  455. // Give focus back of Select
  456. const activeTimeoutIds = [];
  457. onMounted(() => {
  458. activeTimeoutIds.forEach(timeoutId => clearTimeout(timeoutId));
  459. activeTimeoutIds.splice(0, activeTimeoutIds.length);
  460. });
  461. onBeforeUnmount(() => {
  462. activeTimeoutIds.forEach(timeoutId => clearTimeout(timeoutId));
  463. activeTimeoutIds.splice(0, activeTimeoutIds.length);
  464. });
  465. const onInternalMouseDown = function (event) {
  466. var _a, _b;
  467. const {
  468. target
  469. } = event;
  470. const popupElement = (_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.getPopupElement();
  471. // We should give focus back to selector if clicked item is not focusable
  472. if (popupElement && popupElement.contains(target)) {
  473. const timeoutId = setTimeout(() => {
  474. var _a;
  475. const index = activeTimeoutIds.indexOf(timeoutId);
  476. if (index !== -1) {
  477. activeTimeoutIds.splice(index, 1);
  478. }
  479. cancelSetMockFocused();
  480. if (!mobile.value && !popupElement.contains(document.activeElement)) {
  481. (_a = selectorRef.value) === null || _a === void 0 ? void 0 : _a.focus();
  482. }
  483. });
  484. activeTimeoutIds.push(timeoutId);
  485. }
  486. for (var _len3 = arguments.length, restArgs = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
  487. restArgs[_key3 - 1] = arguments[_key3];
  488. }
  489. (_b = props.onMousedown) === null || _b === void 0 ? void 0 : _b.call(props, event, ...restArgs);
  490. };
  491. // ============================= Dropdown ==============================
  492. const containerWidth = shallowRef(null);
  493. // const instance = getCurrentInstance();
  494. const onPopupMouseEnter = () => {
  495. // We need force update here since popup dom is render async
  496. // instance.update();
  497. };
  498. onMounted(() => {
  499. watch(triggerOpen, () => {
  500. var _a;
  501. if (triggerOpen.value) {
  502. const newWidth = Math.ceil((_a = containerRef.value) === null || _a === void 0 ? void 0 : _a.offsetWidth);
  503. if (containerWidth.value !== newWidth && !Number.isNaN(newWidth)) {
  504. containerWidth.value = newWidth;
  505. }
  506. }
  507. }, {
  508. immediate: true,
  509. flush: 'post'
  510. });
  511. });
  512. // Close when click on non-select element
  513. useSelectTriggerControl([containerRef, triggerRef], triggerOpen, onToggleOpen);
  514. useProvideBaseSelectProps(toReactive(_extends(_extends({}, toRefs(props)), {
  515. open: mergedOpen,
  516. triggerOpen,
  517. showSearch: mergedShowSearch,
  518. multiple,
  519. toggleOpen: onToggleOpen
  520. })));
  521. return () => {
  522. const _a = _extends(_extends({}, props), attrs),
  523. {
  524. prefixCls,
  525. id,
  526. open,
  527. defaultOpen,
  528. mode,
  529. // Search related
  530. showSearch,
  531. searchValue,
  532. onSearch,
  533. // Icons
  534. allowClear,
  535. clearIcon,
  536. showArrow,
  537. inputIcon,
  538. // Others
  539. disabled,
  540. loading,
  541. getInputElement,
  542. getPopupContainer,
  543. placement,
  544. // Dropdown
  545. animation,
  546. transitionName,
  547. dropdownStyle,
  548. dropdownClassName,
  549. dropdownMatchSelectWidth,
  550. dropdownRender,
  551. dropdownAlign,
  552. showAction,
  553. direction,
  554. // Tags
  555. tokenSeparators,
  556. tagRender,
  557. optionLabelRender,
  558. // Events
  559. onPopupScroll,
  560. onDropdownVisibleChange,
  561. onFocus,
  562. onBlur,
  563. onKeyup,
  564. onKeydown,
  565. onMousedown,
  566. onClear,
  567. omitDomProps,
  568. getRawInputElement,
  569. displayValues,
  570. onDisplayValuesChange,
  571. emptyOptions,
  572. activeDescendantId,
  573. activeValue,
  574. OptionList
  575. } = _a,
  576. restProps = __rest(_a, ["prefixCls", "id", "open", "defaultOpen", "mode", "showSearch", "searchValue", "onSearch", "allowClear", "clearIcon", "showArrow", "inputIcon", "disabled", "loading", "getInputElement", "getPopupContainer", "placement", "animation", "transitionName", "dropdownStyle", "dropdownClassName", "dropdownMatchSelectWidth", "dropdownRender", "dropdownAlign", "showAction", "direction", "tokenSeparators", "tagRender", "optionLabelRender", "onPopupScroll", "onDropdownVisibleChange", "onFocus", "onBlur", "onKeyup", "onKeydown", "onMousedown", "onClear", "omitDomProps", "getRawInputElement", "displayValues", "onDisplayValuesChange", "emptyOptions", "activeDescendantId", "activeValue", "OptionList"]);
  577. // ============================= Input ==============================
  578. // Only works in `combobox`
  579. const customizeInputElement = mode === 'combobox' && getInputElement && getInputElement() || null;
  580. // Used for customize replacement for `vc-cascader`
  581. const customizeRawInputElement = typeof getRawInputElement === 'function' && getRawInputElement();
  582. const domProps = _extends({}, restProps);
  583. // Used for raw custom input trigger
  584. let onTriggerVisibleChange;
  585. if (customizeRawInputElement) {
  586. onTriggerVisibleChange = newOpen => {
  587. onToggleOpen(newOpen);
  588. };
  589. }
  590. DEFAULT_OMIT_PROPS.forEach(propName => {
  591. delete domProps[propName];
  592. });
  593. omitDomProps === null || omitDomProps === void 0 ? void 0 : omitDomProps.forEach(propName => {
  594. delete domProps[propName];
  595. });
  596. // ============================= Arrow ==============================
  597. const mergedShowArrow = showArrow !== undefined ? showArrow : loading || !multiple.value && mode !== 'combobox';
  598. let arrowNode;
  599. if (mergedShowArrow) {
  600. arrowNode = _createVNode(TransBtn, {
  601. "class": classNames(`${prefixCls}-arrow`, {
  602. [`${prefixCls}-arrow-loading`]: loading
  603. }),
  604. "customizeIcon": inputIcon,
  605. "customizeIconProps": {
  606. loading,
  607. searchValue: mergedSearchValue.value,
  608. open: mergedOpen.value,
  609. focused: mockFocused.value,
  610. showSearch: mergedShowSearch.value
  611. }
  612. }, null);
  613. }
  614. // ============================= Clear ==============================
  615. let clearNode;
  616. const onClearMouseDown = () => {
  617. onClear === null || onClear === void 0 ? void 0 : onClear();
  618. onDisplayValuesChange([], {
  619. type: 'clear',
  620. values: displayValues
  621. });
  622. onInternalSearch('', false, false);
  623. };
  624. if (!disabled && allowClear && (displayValues.length || mergedSearchValue.value)) {
  625. clearNode = _createVNode(TransBtn, {
  626. "class": `${prefixCls}-clear`,
  627. "onMousedown": onClearMouseDown,
  628. "customizeIcon": clearIcon
  629. }, {
  630. default: () => [_createTextVNode("\xD7")]
  631. });
  632. }
  633. // =========================== OptionList ===========================
  634. const optionList = _createVNode(OptionList, {
  635. "ref": listRef
  636. }, _extends(_extends({}, legacyTreeSelectContext.customSlots), {
  637. option: slots.option
  638. }));
  639. // ============================= Select =============================
  640. const mergedClassName = classNames(prefixCls, attrs.class, {
  641. [`${prefixCls}-focused`]: mockFocused.value,
  642. [`${prefixCls}-multiple`]: multiple.value,
  643. [`${prefixCls}-single`]: !multiple.value,
  644. [`${prefixCls}-allow-clear`]: allowClear,
  645. [`${prefixCls}-show-arrow`]: mergedShowArrow,
  646. [`${prefixCls}-disabled`]: disabled,
  647. [`${prefixCls}-loading`]: loading,
  648. [`${prefixCls}-open`]: mergedOpen.value,
  649. [`${prefixCls}-customize-input`]: customizeInputElement,
  650. [`${prefixCls}-show-search`]: mergedShowSearch.value
  651. });
  652. // >>> Selector
  653. const selectorNode = _createVNode(SelectTrigger, {
  654. "ref": triggerRef,
  655. "disabled": disabled,
  656. "prefixCls": prefixCls,
  657. "visible": triggerOpen.value,
  658. "popupElement": optionList,
  659. "containerWidth": containerWidth.value,
  660. "animation": animation,
  661. "transitionName": transitionName,
  662. "dropdownStyle": dropdownStyle,
  663. "dropdownClassName": dropdownClassName,
  664. "direction": direction,
  665. "dropdownMatchSelectWidth": dropdownMatchSelectWidth,
  666. "dropdownRender": dropdownRender,
  667. "dropdownAlign": dropdownAlign,
  668. "placement": placement,
  669. "getPopupContainer": getPopupContainer,
  670. "empty": emptyOptions,
  671. "getTriggerDOMNode": () => selectorDomRef.current,
  672. "onPopupVisibleChange": onTriggerVisibleChange,
  673. "onPopupMouseEnter": onPopupMouseEnter,
  674. "onPopupFocusin": onPopupFocusin,
  675. "onPopupFocusout": onPopupFocusout
  676. }, {
  677. default: () => {
  678. return customizeRawInputElement ? isValidElement(customizeRawInputElement) && cloneElement(customizeRawInputElement, {
  679. ref: selectorDomRef
  680. }, false, true) : _createVNode(Selector, _objectSpread(_objectSpread({}, props), {}, {
  681. "domRef": selectorDomRef,
  682. "prefixCls": prefixCls,
  683. "inputElement": customizeInputElement,
  684. "ref": selectorRef,
  685. "id": id,
  686. "showSearch": mergedShowSearch.value,
  687. "mode": mode,
  688. "activeDescendantId": activeDescendantId,
  689. "tagRender": tagRender,
  690. "optionLabelRender": optionLabelRender,
  691. "values": displayValues,
  692. "open": mergedOpen.value,
  693. "onToggleOpen": onToggleOpen,
  694. "activeValue": activeValue,
  695. "searchValue": mergedSearchValue.value,
  696. "onSearch": onInternalSearch,
  697. "onSearchSubmit": onInternalSearchSubmit,
  698. "onRemove": onSelectorRemove,
  699. "tokenWithEnter": tokenWithEnter.value
  700. }), null);
  701. }
  702. });
  703. // >>> Render
  704. let renderNode;
  705. // Render raw
  706. if (customizeRawInputElement) {
  707. renderNode = selectorNode;
  708. } else {
  709. renderNode = _createVNode("div", _objectSpread(_objectSpread({}, domProps), {}, {
  710. "class": mergedClassName,
  711. "ref": containerRef,
  712. "onMousedown": onInternalMouseDown,
  713. "onKeydown": onInternalKeyDown,
  714. "onKeyup": onInternalKeyUp
  715. }), [mockFocused.value && !mergedOpen.value && _createVNode("span", {
  716. "style": {
  717. width: 0,
  718. height: 0,
  719. position: 'absolute',
  720. overflow: 'hidden',
  721. opacity: 0
  722. },
  723. "aria-live": "polite"
  724. }, [`${displayValues.map(_ref2 => {
  725. let {
  726. label,
  727. value
  728. } = _ref2;
  729. return ['number', 'string'].includes(typeof label) ? label : value;
  730. }).join(', ')}`]), selectorNode, arrowNode, clearNode]);
  731. }
  732. return renderNode;
  733. };
  734. }
  735. });