87fb3352ab30b6f2ab98ee5d1b6cd7eb264738738877c18be8c0f5769a938afc5174c565aee085b14da5aa09f150cbbcb38f0e675e624ad38fed2554983e68 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import { inject, ref, computed, nextTick, watch } from 'vue';
  2. import { debounce } from 'lodash-unified';
  3. import { useEventListener } from '@vueuse/core';
  4. import { sliderContextKey } from '../constants.mjs';
  5. import { EVENT_CODE } from '../../../../constants/aria.mjs';
  6. import { UPDATE_MODEL_EVENT } from '../../../../constants/event.mjs';
  7. const useTooltip = (props, formatTooltip, showTooltip) => {
  8. const tooltip = ref();
  9. const tooltipVisible = ref(false);
  10. const enableFormat = computed(() => {
  11. return formatTooltip.value instanceof Function;
  12. });
  13. const formatValue = computed(() => {
  14. return enableFormat.value && formatTooltip.value(props.modelValue) || props.modelValue;
  15. });
  16. const displayTooltip = debounce(() => {
  17. showTooltip.value && (tooltipVisible.value = true);
  18. }, 50);
  19. const hideTooltip = debounce(() => {
  20. showTooltip.value && (tooltipVisible.value = false);
  21. }, 50);
  22. return {
  23. tooltip,
  24. tooltipVisible,
  25. formatValue,
  26. displayTooltip,
  27. hideTooltip
  28. };
  29. };
  30. const useSliderButton = (props, initData, emit) => {
  31. const {
  32. disabled,
  33. min,
  34. max,
  35. step,
  36. showTooltip,
  37. persistent,
  38. precision,
  39. sliderSize,
  40. formatTooltip,
  41. emitChange,
  42. resetSize,
  43. updateDragging
  44. } = inject(sliderContextKey);
  45. const { tooltip, tooltipVisible, formatValue, displayTooltip, hideTooltip } = useTooltip(props, formatTooltip, showTooltip);
  46. const button = ref();
  47. const currentPosition = computed(() => {
  48. return `${(props.modelValue - min.value) / (max.value - min.value) * 100}%`;
  49. });
  50. const wrapperStyle = computed(() => {
  51. return props.vertical ? { bottom: currentPosition.value } : { left: currentPosition.value };
  52. });
  53. const handleMouseEnter = () => {
  54. initData.hovering = true;
  55. displayTooltip();
  56. };
  57. const handleMouseLeave = () => {
  58. initData.hovering = false;
  59. if (!initData.dragging) {
  60. hideTooltip();
  61. }
  62. };
  63. const onButtonDown = (event) => {
  64. if (disabled.value)
  65. return;
  66. event.preventDefault();
  67. onDragStart(event);
  68. window.addEventListener("mousemove", onDragging);
  69. window.addEventListener("touchmove", onDragging);
  70. window.addEventListener("mouseup", onDragEnd);
  71. window.addEventListener("touchend", onDragEnd);
  72. window.addEventListener("contextmenu", onDragEnd);
  73. button.value.focus();
  74. };
  75. const incrementPosition = (amount) => {
  76. if (disabled.value)
  77. return;
  78. initData.newPosition = Number.parseFloat(currentPosition.value) + amount / (max.value - min.value) * 100;
  79. setPosition(initData.newPosition);
  80. emitChange();
  81. };
  82. const onLeftKeyDown = () => {
  83. incrementPosition(-step.value);
  84. };
  85. const onRightKeyDown = () => {
  86. incrementPosition(step.value);
  87. };
  88. const onPageDownKeyDown = () => {
  89. incrementPosition(-step.value * 4);
  90. };
  91. const onPageUpKeyDown = () => {
  92. incrementPosition(step.value * 4);
  93. };
  94. const onHomeKeyDown = () => {
  95. if (disabled.value)
  96. return;
  97. setPosition(0);
  98. emitChange();
  99. };
  100. const onEndKeyDown = () => {
  101. if (disabled.value)
  102. return;
  103. setPosition(100);
  104. emitChange();
  105. };
  106. const onKeyDown = (event) => {
  107. let isPreventDefault = true;
  108. switch (event.code) {
  109. case EVENT_CODE.left:
  110. case EVENT_CODE.down:
  111. onLeftKeyDown();
  112. break;
  113. case EVENT_CODE.right:
  114. case EVENT_CODE.up:
  115. onRightKeyDown();
  116. break;
  117. case EVENT_CODE.home:
  118. onHomeKeyDown();
  119. break;
  120. case EVENT_CODE.end:
  121. onEndKeyDown();
  122. break;
  123. case EVENT_CODE.pageDown:
  124. onPageDownKeyDown();
  125. break;
  126. case EVENT_CODE.pageUp:
  127. onPageUpKeyDown();
  128. break;
  129. default:
  130. isPreventDefault = false;
  131. break;
  132. }
  133. isPreventDefault && event.preventDefault();
  134. };
  135. const getClientXY = (event) => {
  136. let clientX;
  137. let clientY;
  138. if (event.type.startsWith("touch")) {
  139. clientY = event.touches[0].clientY;
  140. clientX = event.touches[0].clientX;
  141. } else {
  142. clientY = event.clientY;
  143. clientX = event.clientX;
  144. }
  145. return {
  146. clientX,
  147. clientY
  148. };
  149. };
  150. const onDragStart = (event) => {
  151. initData.dragging = true;
  152. initData.isClick = true;
  153. const { clientX, clientY } = getClientXY(event);
  154. if (props.vertical) {
  155. initData.startY = clientY;
  156. } else {
  157. initData.startX = clientX;
  158. }
  159. initData.startPosition = Number.parseFloat(currentPosition.value);
  160. initData.newPosition = initData.startPosition;
  161. };
  162. const onDragging = (event) => {
  163. if (initData.dragging) {
  164. initData.isClick = false;
  165. displayTooltip();
  166. resetSize();
  167. let diff;
  168. const { clientX, clientY } = getClientXY(event);
  169. if (props.vertical) {
  170. initData.currentY = clientY;
  171. diff = (initData.startY - initData.currentY) / sliderSize.value * 100;
  172. } else {
  173. initData.currentX = clientX;
  174. diff = (initData.currentX - initData.startX) / sliderSize.value * 100;
  175. }
  176. initData.newPosition = initData.startPosition + diff;
  177. setPosition(initData.newPosition);
  178. }
  179. };
  180. const onDragEnd = () => {
  181. if (initData.dragging) {
  182. setTimeout(() => {
  183. initData.dragging = false;
  184. if (!initData.hovering) {
  185. hideTooltip();
  186. }
  187. if (!initData.isClick) {
  188. setPosition(initData.newPosition);
  189. }
  190. emitChange();
  191. }, 0);
  192. window.removeEventListener("mousemove", onDragging);
  193. window.removeEventListener("touchmove", onDragging);
  194. window.removeEventListener("mouseup", onDragEnd);
  195. window.removeEventListener("touchend", onDragEnd);
  196. window.removeEventListener("contextmenu", onDragEnd);
  197. }
  198. };
  199. const setPosition = async (newPosition) => {
  200. if (newPosition === null || Number.isNaN(+newPosition))
  201. return;
  202. if (newPosition < 0) {
  203. newPosition = 0;
  204. } else if (newPosition > 100) {
  205. newPosition = 100;
  206. }
  207. const lengthPerStep = 100 / ((max.value - min.value) / step.value);
  208. const steps = Math.round(newPosition / lengthPerStep);
  209. let value = steps * lengthPerStep * (max.value - min.value) * 0.01 + min.value;
  210. value = Number.parseFloat(value.toFixed(precision.value));
  211. if (value !== props.modelValue) {
  212. emit(UPDATE_MODEL_EVENT, value);
  213. }
  214. if (!initData.dragging && props.modelValue !== initData.oldValue) {
  215. initData.oldValue = props.modelValue;
  216. }
  217. await nextTick();
  218. initData.dragging && displayTooltip();
  219. tooltip.value.updatePopper();
  220. };
  221. watch(() => initData.dragging, (val) => {
  222. updateDragging(val);
  223. });
  224. useEventListener(button, "touchstart", onButtonDown, { passive: false });
  225. return {
  226. disabled,
  227. button,
  228. tooltip,
  229. tooltipVisible,
  230. showTooltip,
  231. persistent,
  232. wrapperStyle,
  233. formatValue,
  234. handleMouseEnter,
  235. handleMouseLeave,
  236. onButtonDown,
  237. onKeyDown,
  238. setPosition
  239. };
  240. };
  241. export { useSliderButton };
  242. //# sourceMappingURL=use-slider-button.mjs.map