DropdownMenu.mjs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { ref, computed, defineComponent, createVNode as _createVNode } from "vue";
  2. import { isDef, truthProp, numericProp, windowHeight, makeStringProp, makeNumericProp, createNamespace, HAPTICS_FEEDBACK } from "../utils/index.mjs";
  3. import { useId } from "../composables/use-id.mjs";
  4. import { useExpose } from "../composables/use-expose.mjs";
  5. import { useRect, useChildren, useClickAway, useScrollParent, useEventListener } from "@vant/use";
  6. const [name, bem] = createNamespace("dropdown-menu");
  7. const dropdownMenuProps = {
  8. overlay: truthProp,
  9. zIndex: numericProp,
  10. duration: makeNumericProp(0.2),
  11. direction: makeStringProp("down"),
  12. activeColor: String,
  13. autoLocate: Boolean,
  14. closeOnClickOutside: truthProp,
  15. closeOnClickOverlay: truthProp,
  16. swipeThreshold: numericProp
  17. };
  18. const DROPDOWN_KEY = Symbol(name);
  19. var stdin_default = defineComponent({
  20. name,
  21. props: dropdownMenuProps,
  22. setup(props, {
  23. slots
  24. }) {
  25. const id = useId();
  26. const root = ref();
  27. const barRef = ref();
  28. const offset = ref(0);
  29. const {
  30. children,
  31. linkChildren
  32. } = useChildren(DROPDOWN_KEY);
  33. const scrollParent = useScrollParent(root);
  34. const opened = computed(() => children.some((item) => item.state.showWrapper));
  35. const scrollable = computed(() => props.swipeThreshold && children.length > +props.swipeThreshold);
  36. const barStyle = computed(() => {
  37. if (opened.value && isDef(props.zIndex)) {
  38. return {
  39. zIndex: +props.zIndex + 1
  40. };
  41. }
  42. });
  43. const close = () => {
  44. children.forEach((item) => {
  45. item.toggle(false);
  46. });
  47. };
  48. const onClickAway = () => {
  49. if (props.closeOnClickOutside) {
  50. close();
  51. }
  52. };
  53. const updateOffset = () => {
  54. if (barRef.value) {
  55. const rect = useRect(barRef);
  56. if (props.direction === "down") {
  57. offset.value = rect.bottom;
  58. } else {
  59. offset.value = windowHeight.value - rect.top;
  60. }
  61. }
  62. };
  63. const onScroll = () => {
  64. if (opened.value) {
  65. updateOffset();
  66. }
  67. };
  68. const toggleItem = (active) => {
  69. children.forEach((item, index) => {
  70. if (index === active) {
  71. item.toggle();
  72. } else if (item.state.showPopup) {
  73. item.toggle(false, {
  74. immediate: true
  75. });
  76. }
  77. });
  78. };
  79. const renderTitle = (item, index) => {
  80. const {
  81. showPopup
  82. } = item.state;
  83. const {
  84. disabled,
  85. titleClass
  86. } = item;
  87. return _createVNode("div", {
  88. "id": `${id}-${index}`,
  89. "role": "button",
  90. "tabindex": disabled ? void 0 : 0,
  91. "data-allow-mismatch": "attribute",
  92. "class": [bem("item", {
  93. disabled,
  94. grow: scrollable.value
  95. }), {
  96. [HAPTICS_FEEDBACK]: !disabled
  97. }],
  98. "onClick": () => {
  99. if (!disabled) {
  100. toggleItem(index);
  101. }
  102. }
  103. }, [_createVNode("span", {
  104. "class": [bem("title", {
  105. down: showPopup === (props.direction === "down"),
  106. active: showPopup
  107. }), titleClass],
  108. "style": {
  109. color: showPopup ? props.activeColor : ""
  110. }
  111. }, [_createVNode("div", {
  112. "class": "van-ellipsis"
  113. }, [item.renderTitle()])])]);
  114. };
  115. useExpose({
  116. close
  117. });
  118. linkChildren({
  119. id,
  120. props,
  121. offset,
  122. updateOffset
  123. });
  124. useClickAway(root, onClickAway);
  125. useEventListener("scroll", onScroll, {
  126. target: scrollParent,
  127. passive: true
  128. });
  129. return () => {
  130. var _a;
  131. return _createVNode("div", {
  132. "ref": root,
  133. "class": bem()
  134. }, [_createVNode("div", {
  135. "ref": barRef,
  136. "style": barStyle.value,
  137. "class": bem("bar", {
  138. opened: opened.value,
  139. scrollable: scrollable.value
  140. })
  141. }, [children.map(renderTitle)]), (_a = slots.default) == null ? void 0 : _a.call(slots)]);
  142. };
  143. }
  144. });
  145. export {
  146. DROPDOWN_KEY,
  147. stdin_default as default,
  148. dropdownMenuProps
  149. };