select-dropdown.mjs 6.5 KB

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