DropdownItem.mjs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import { reactive, Teleport, defineComponent, ref, createVNode as _createVNode, vShow as _vShow, mergeProps as _mergeProps, withDirectives as _withDirectives } from "vue";
  2. import { truthProp, unknownProp, getZIndexStyle, createNamespace, makeArrayProp, getContainingBlock } from "../utils/index.mjs";
  3. import { DROPDOWN_KEY } from "../dropdown-menu/DropdownMenu.mjs";
  4. import { useParent, useRect } from "@vant/use";
  5. import { useExpose } from "../composables/use-expose.mjs";
  6. import { Cell } from "../cell/index.mjs";
  7. import { Icon } from "../icon/index.mjs";
  8. import { Popup } from "../popup/index.mjs";
  9. const [name, bem] = createNamespace("dropdown-item");
  10. const dropdownItemProps = {
  11. title: String,
  12. options: makeArrayProp(),
  13. disabled: Boolean,
  14. teleport: [String, Object],
  15. lazyRender: truthProp,
  16. modelValue: unknownProp,
  17. titleClass: unknownProp
  18. };
  19. var stdin_default = defineComponent({
  20. name,
  21. inheritAttrs: false,
  22. props: dropdownItemProps,
  23. emits: ["open", "opened", "close", "closed", "change", "update:modelValue"],
  24. setup(props, {
  25. emit,
  26. slots,
  27. attrs
  28. }) {
  29. const state = reactive({
  30. showPopup: false,
  31. transition: true,
  32. showWrapper: false
  33. });
  34. const wrapperRef = ref();
  35. const {
  36. parent,
  37. index
  38. } = useParent(DROPDOWN_KEY);
  39. if (!parent) {
  40. if (process.env.NODE_ENV !== "production") {
  41. console.error("[Vant] <DropdownItem> must be a child component of <DropdownMenu>.");
  42. }
  43. return;
  44. }
  45. const getEmitter = (name2) => () => emit(name2);
  46. const onOpen = getEmitter("open");
  47. const onClose = getEmitter("close");
  48. const onOpened = getEmitter("opened");
  49. const onClosed = () => {
  50. state.showWrapper = false;
  51. emit("closed");
  52. };
  53. const onClickWrapper = (event) => {
  54. if (props.teleport) {
  55. event.stopPropagation();
  56. }
  57. };
  58. const toggle = (show = !state.showPopup, options = {}) => {
  59. if (show === state.showPopup) {
  60. return;
  61. }
  62. state.showPopup = show;
  63. state.transition = !options.immediate;
  64. if (show) {
  65. parent.updateOffset();
  66. state.showWrapper = true;
  67. }
  68. };
  69. const renderTitle = () => {
  70. if (slots.title) {
  71. return slots.title();
  72. }
  73. if (props.title) {
  74. return props.title;
  75. }
  76. const match = props.options.find((option) => option.value === props.modelValue);
  77. return match ? match.text : "";
  78. };
  79. const renderOption = (option) => {
  80. const {
  81. activeColor
  82. } = parent.props;
  83. const {
  84. disabled
  85. } = option;
  86. const active = option.value === props.modelValue;
  87. const onClick = () => {
  88. if (disabled) {
  89. return;
  90. }
  91. state.showPopup = false;
  92. if (option.value !== props.modelValue) {
  93. emit("update:modelValue", option.value);
  94. emit("change", option.value);
  95. }
  96. };
  97. const renderIcon = () => {
  98. if (active) {
  99. return _createVNode(Icon, {
  100. "class": bem("icon"),
  101. "color": disabled ? void 0 : activeColor,
  102. "name": "success"
  103. }, null);
  104. }
  105. };
  106. return _createVNode(Cell, {
  107. "role": "menuitem",
  108. "key": String(option.value),
  109. "icon": option.icon,
  110. "title": option.text,
  111. "class": bem("option", {
  112. active,
  113. disabled
  114. }),
  115. "style": {
  116. color: active ? activeColor : ""
  117. },
  118. "tabindex": active ? 0 : -1,
  119. "clickable": !disabled,
  120. "onClick": onClick
  121. }, {
  122. value: renderIcon
  123. });
  124. };
  125. const renderContent = () => {
  126. const {
  127. offset
  128. } = parent;
  129. const {
  130. autoLocate,
  131. zIndex,
  132. overlay,
  133. duration,
  134. direction,
  135. closeOnClickOverlay
  136. } = parent.props;
  137. const style = getZIndexStyle(zIndex);
  138. let offsetValue = offset.value;
  139. if (autoLocate && wrapperRef.value) {
  140. const offsetParent = getContainingBlock(wrapperRef.value);
  141. if (offsetParent) {
  142. offsetValue -= useRect(offsetParent).top;
  143. }
  144. }
  145. if (direction === "down") {
  146. style.top = `${offsetValue}px`;
  147. } else {
  148. style.bottom = `${offsetValue}px`;
  149. }
  150. return _withDirectives(_createVNode("div", _mergeProps({
  151. "ref": wrapperRef,
  152. "style": style,
  153. "class": bem([direction]),
  154. "onClick": onClickWrapper
  155. }, attrs), [_createVNode(Popup, {
  156. "show": state.showPopup,
  157. "onUpdate:show": ($event) => state.showPopup = $event,
  158. "role": "menu",
  159. "class": bem("content"),
  160. "overlay": overlay,
  161. "position": direction === "down" ? "top" : "bottom",
  162. "duration": state.transition ? duration : 0,
  163. "lazyRender": props.lazyRender,
  164. "overlayStyle": {
  165. position: "absolute"
  166. },
  167. "aria-labelledby": `${parent.id}-${index.value}`,
  168. "data-allow-mismatch": "attribute",
  169. "closeOnClickOverlay": closeOnClickOverlay,
  170. "onOpen": onOpen,
  171. "onClose": onClose,
  172. "onOpened": onOpened,
  173. "onClosed": onClosed
  174. }, {
  175. default: () => {
  176. var _a;
  177. return [props.options.map(renderOption), (_a = slots.default) == null ? void 0 : _a.call(slots)];
  178. }
  179. })]), [[_vShow, state.showWrapper]]);
  180. };
  181. useExpose({
  182. state,
  183. toggle,
  184. renderTitle
  185. });
  186. return () => {
  187. if (props.teleport) {
  188. return _createVNode(Teleport, {
  189. "to": props.teleport
  190. }, {
  191. default: () => [renderContent()]
  192. });
  193. }
  194. return renderContent();
  195. };
  196. }
  197. });
  198. export {
  199. stdin_default as default,
  200. dropdownItemProps
  201. };