select-dropdown.mjs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import { defineComponent, inject, ref, computed, watch, unref, createVNode, mergeProps, toRaw } from 'vue';
  2. import { get } from 'lodash-unified';
  3. import GroupItem from './group-item.mjs';
  4. import OptionItem from './option-item.mjs';
  5. import { useProps } from './useProps.mjs';
  6. import { selectV2InjectionKey } from './token.mjs';
  7. import FixedSizeList from '../../virtual-list/src/components/fixed-size-list.mjs';
  8. import DynamicSizeList from '../../virtual-list/src/components/dynamic-size-list.mjs';
  9. import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
  10. import { isUndefined } from '../../../utils/types.mjs';
  11. import { isIOS } from '@vueuse/core';
  12. import { EVENT_CODE } from '../../../constants/aria.mjs';
  13. import { isObject } from '@vue/shared';
  14. const props = {
  15. loading: Boolean,
  16. data: {
  17. type: Array,
  18. required: true
  19. },
  20. hoveringIndex: Number,
  21. width: Number
  22. };
  23. var ElSelectMenu = defineComponent({
  24. name: "ElSelectDropdown",
  25. props,
  26. setup(props2, {
  27. slots,
  28. expose
  29. }) {
  30. const select = inject(selectV2InjectionKey);
  31. const ns = useNamespace("select");
  32. const {
  33. getLabel,
  34. getValue,
  35. getDisabled
  36. } = useProps(select.props);
  37. const cachedHeights = ref([]);
  38. const listRef = ref();
  39. const size = computed(() => props2.data.length);
  40. watch(() => size.value, () => {
  41. var _a, _b;
  42. (_b = (_a = select.tooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a);
  43. });
  44. const isSized = computed(() => isUndefined(select.props.estimatedOptionHeight));
  45. const listProps = computed(() => {
  46. if (isSized.value) {
  47. return {
  48. itemSize: select.props.itemHeight
  49. };
  50. }
  51. return {
  52. estimatedSize: select.props.estimatedOptionHeight,
  53. itemSize: (idx) => cachedHeights.value[idx]
  54. };
  55. });
  56. const contains = (arr = [], target) => {
  57. const {
  58. props: {
  59. valueKey
  60. }
  61. } = select;
  62. if (!isObject(target)) {
  63. return arr.includes(target);
  64. }
  65. return arr && arr.some((item) => {
  66. return toRaw(get(item, valueKey)) === get(target, valueKey);
  67. });
  68. };
  69. const isEqual = (selected, target) => {
  70. if (!isObject(target)) {
  71. return selected === target;
  72. } else {
  73. const {
  74. valueKey
  75. } = select.props;
  76. return get(selected, valueKey) === get(target, valueKey);
  77. }
  78. };
  79. const isItemSelected = (modelValue, target) => {
  80. if (select.props.multiple) {
  81. return contains(modelValue, getValue(target));
  82. }
  83. return isEqual(modelValue, getValue(target));
  84. };
  85. const isItemDisabled = (modelValue, selected) => {
  86. const {
  87. disabled,
  88. multiple,
  89. multipleLimit
  90. } = select.props;
  91. return disabled || !selected && (multiple ? multipleLimit > 0 && modelValue.length >= multipleLimit : false);
  92. };
  93. const isItemHovering = (target) => props2.hoveringIndex === target;
  94. const scrollToItem = (index) => {
  95. const list = listRef.value;
  96. if (list) {
  97. list.scrollToItem(index);
  98. }
  99. };
  100. const resetScrollTop = () => {
  101. const list = listRef.value;
  102. if (list) {
  103. list.resetScrollTop();
  104. }
  105. };
  106. const exposed = {
  107. listRef,
  108. isSized,
  109. isItemDisabled,
  110. isItemHovering,
  111. isItemSelected,
  112. scrollToItem,
  113. resetScrollTop
  114. };
  115. expose(exposed);
  116. const Item = (itemProps) => {
  117. const {
  118. index,
  119. data,
  120. style
  121. } = itemProps;
  122. const sized = unref(isSized);
  123. const {
  124. itemSize,
  125. estimatedSize
  126. } = unref(listProps);
  127. const {
  128. modelValue
  129. } = select.props;
  130. const {
  131. onSelect,
  132. onHover
  133. } = select;
  134. const item = data[index];
  135. if (item.type === "Group") {
  136. return createVNode(GroupItem, {
  137. "item": item,
  138. "style": style,
  139. "height": sized ? itemSize : estimatedSize
  140. }, null);
  141. }
  142. const isSelected = isItemSelected(modelValue, item);
  143. const isDisabled = isItemDisabled(modelValue, isSelected);
  144. const isHovering = isItemHovering(index);
  145. return createVNode(OptionItem, mergeProps(itemProps, {
  146. "selected": isSelected,
  147. "disabled": getDisabled(item) || isDisabled,
  148. "created": !!item.created,
  149. "hovering": isHovering,
  150. "item": item,
  151. "onSelect": onSelect,
  152. "onHover": onHover
  153. }), {
  154. default: (props3) => {
  155. var _a;
  156. return ((_a = slots.default) == null ? void 0 : _a.call(slots, props3)) || createVNode("span", null, [getLabel(item)]);
  157. }
  158. });
  159. };
  160. const {
  161. onKeyboardNavigate,
  162. onKeyboardSelect
  163. } = select;
  164. const onForward = () => {
  165. onKeyboardNavigate("forward");
  166. };
  167. const onBackward = () => {
  168. onKeyboardNavigate("backward");
  169. };
  170. const onKeydown = (e) => {
  171. const {
  172. code
  173. } = e;
  174. const {
  175. tab,
  176. esc,
  177. down,
  178. up,
  179. enter,
  180. numpadEnter
  181. } = EVENT_CODE;
  182. if ([esc, down, up, enter, numpadEnter].includes(code)) {
  183. e.preventDefault();
  184. e.stopPropagation();
  185. }
  186. switch (code) {
  187. case tab:
  188. case esc:
  189. break;
  190. case down:
  191. onForward();
  192. break;
  193. case up:
  194. onBackward();
  195. break;
  196. case enter:
  197. case numpadEnter:
  198. onKeyboardSelect();
  199. break;
  200. }
  201. };
  202. return () => {
  203. var _a, _b, _c, _d;
  204. const {
  205. data,
  206. width
  207. } = props2;
  208. const {
  209. height,
  210. multiple,
  211. scrollbarAlwaysOn
  212. } = select.props;
  213. const isScrollbarAlwaysOn = computed(() => {
  214. return isIOS ? true : scrollbarAlwaysOn;
  215. });
  216. const List = unref(isSized) ? FixedSizeList : DynamicSizeList;
  217. return createVNode("div", {
  218. "class": [ns.b("dropdown"), ns.is("multiple", multiple)],
  219. "style": {
  220. width: `${width}px`
  221. }
  222. }, [(_a = slots.header) == null ? void 0 : _a.call(slots), ((_b = slots.loading) == null ? void 0 : _b.call(slots)) || ((_c = slots.empty) == null ? void 0 : _c.call(slots)) || createVNode(List, mergeProps({
  223. "ref": listRef
  224. }, unref(listProps), {
  225. "className": ns.be("dropdown", "list"),
  226. "scrollbarAlwaysOn": isScrollbarAlwaysOn.value,
  227. "data": data,
  228. "height": height,
  229. "width": width,
  230. "total": data.length,
  231. "onKeydown": onKeydown
  232. }), {
  233. default: (props3) => createVNode(Item, props3, null)
  234. }), (_d = slots.footer) == null ? void 0 : _d.call(slots)]);
  235. };
  236. }
  237. });
  238. export { ElSelectMenu as default };
  239. //# sourceMappingURL=select-dropdown.mjs.map