VProgressCircular.mjs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import { createVNode as _createVNode } from "vue";
  2. // Styles
  3. import "./VProgressCircular.css";
  4. // Composables
  5. import { useTextColor } from "../../composables/color.mjs";
  6. import { makeComponentProps } from "../../composables/component.mjs";
  7. import { useIntersectionObserver } from "../../composables/intersectionObserver.mjs";
  8. import { useResizeObserver } from "../../composables/resizeObserver.mjs";
  9. import { makeSizeProps, useSize } from "../../composables/size.mjs";
  10. import { makeTagProps } from "../../composables/tag.mjs";
  11. import { makeThemeProps, provideTheme } from "../../composables/theme.mjs"; // Utilities
  12. import { computed, ref, toRef, watchEffect } from 'vue';
  13. import { convertToUnit, genericComponent, propsFactory, useRender } from "../../util/index.mjs"; // Types
  14. export const makeVProgressCircularProps = propsFactory({
  15. bgColor: String,
  16. color: String,
  17. indeterminate: [Boolean, String],
  18. modelValue: {
  19. type: [Number, String],
  20. default: 0
  21. },
  22. rotate: {
  23. type: [Number, String],
  24. default: 0
  25. },
  26. width: {
  27. type: [Number, String],
  28. default: 4
  29. },
  30. ...makeComponentProps(),
  31. ...makeSizeProps(),
  32. ...makeTagProps({
  33. tag: 'div'
  34. }),
  35. ...makeThemeProps()
  36. }, 'VProgressCircular');
  37. export const VProgressCircular = genericComponent()({
  38. name: 'VProgressCircular',
  39. props: makeVProgressCircularProps(),
  40. setup(props, _ref) {
  41. let {
  42. slots
  43. } = _ref;
  44. const MAGIC_RADIUS_CONSTANT = 20;
  45. const CIRCUMFERENCE = 2 * Math.PI * MAGIC_RADIUS_CONSTANT;
  46. const root = ref();
  47. const {
  48. themeClasses
  49. } = provideTheme(props);
  50. const {
  51. sizeClasses,
  52. sizeStyles
  53. } = useSize(props);
  54. const {
  55. textColorClasses,
  56. textColorStyles
  57. } = useTextColor(toRef(props, 'color'));
  58. const {
  59. textColorClasses: underlayColorClasses,
  60. textColorStyles: underlayColorStyles
  61. } = useTextColor(toRef(props, 'bgColor'));
  62. const {
  63. intersectionRef,
  64. isIntersecting
  65. } = useIntersectionObserver();
  66. const {
  67. resizeRef,
  68. contentRect
  69. } = useResizeObserver();
  70. const normalizedValue = computed(() => Math.max(0, Math.min(100, parseFloat(props.modelValue))));
  71. const width = computed(() => Number(props.width));
  72. const size = computed(() => {
  73. // Get size from element if size prop value is small, large etc
  74. return sizeStyles.value ? Number(props.size) : contentRect.value ? contentRect.value.width : Math.max(width.value, 32);
  75. });
  76. const diameter = computed(() => MAGIC_RADIUS_CONSTANT / (1 - width.value / size.value) * 2);
  77. const strokeWidth = computed(() => width.value / size.value * diameter.value);
  78. const strokeDashOffset = computed(() => convertToUnit((100 - normalizedValue.value) / 100 * CIRCUMFERENCE));
  79. watchEffect(() => {
  80. intersectionRef.value = root.value;
  81. resizeRef.value = root.value;
  82. });
  83. useRender(() => _createVNode(props.tag, {
  84. "ref": root,
  85. "class": ['v-progress-circular', {
  86. 'v-progress-circular--indeterminate': !!props.indeterminate,
  87. 'v-progress-circular--visible': isIntersecting.value,
  88. 'v-progress-circular--disable-shrink': props.indeterminate === 'disable-shrink'
  89. }, themeClasses.value, sizeClasses.value, textColorClasses.value, props.class],
  90. "style": [sizeStyles.value, textColorStyles.value, props.style],
  91. "role": "progressbar",
  92. "aria-valuemin": "0",
  93. "aria-valuemax": "100",
  94. "aria-valuenow": props.indeterminate ? undefined : normalizedValue.value
  95. }, {
  96. default: () => [_createVNode("svg", {
  97. "style": {
  98. transform: `rotate(calc(-90deg + ${Number(props.rotate)}deg))`
  99. },
  100. "xmlns": "http://www.w3.org/2000/svg",
  101. "viewBox": `0 0 ${diameter.value} ${diameter.value}`
  102. }, [_createVNode("circle", {
  103. "class": ['v-progress-circular__underlay', underlayColorClasses.value],
  104. "style": underlayColorStyles.value,
  105. "fill": "transparent",
  106. "cx": "50%",
  107. "cy": "50%",
  108. "r": MAGIC_RADIUS_CONSTANT,
  109. "stroke-width": strokeWidth.value,
  110. "stroke-dasharray": CIRCUMFERENCE,
  111. "stroke-dashoffset": 0
  112. }, null), _createVNode("circle", {
  113. "class": "v-progress-circular__overlay",
  114. "fill": "transparent",
  115. "cx": "50%",
  116. "cy": "50%",
  117. "r": MAGIC_RADIUS_CONSTANT,
  118. "stroke-width": strokeWidth.value,
  119. "stroke-dasharray": CIRCUMFERENCE,
  120. "stroke-dashoffset": strokeDashOffset.value
  121. }, null)]), slots.default && _createVNode("div", {
  122. "class": "v-progress-circular__content"
  123. }, [slots.default({
  124. value: normalizedValue.value
  125. })])]
  126. }));
  127. return {};
  128. }
  129. });
  130. //# sourceMappingURL=VProgressCircular.mjs.map