VTab.mjs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { mergeProps as _mergeProps, createVNode as _createVNode, Fragment as _Fragment } from "vue";
  2. // Styles
  3. import "./VTab.css";
  4. // Components
  5. import { makeVBtnProps, VBtn } from "../VBtn/VBtn.mjs"; // Composables
  6. import { useTextColor } from "../../composables/color.mjs";
  7. import { forwardRefs } from "../../composables/forwardRefs.mjs"; // Utilities
  8. import { computed, ref } from 'vue';
  9. import { VTabsSymbol } from "./shared.mjs";
  10. import { animate, genericComponent, omit, propsFactory, standardEasing, useRender } from "../../util/index.mjs"; // Types
  11. export const makeVTabProps = propsFactory({
  12. fixed: Boolean,
  13. sliderColor: String,
  14. hideSlider: Boolean,
  15. direction: {
  16. type: String,
  17. default: 'horizontal'
  18. },
  19. ...omit(makeVBtnProps({
  20. selectedClass: 'v-tab--selected',
  21. variant: 'text'
  22. }), ['active', 'block', 'flat', 'location', 'position', 'symbol'])
  23. }, 'VTab');
  24. export const VTab = genericComponent()({
  25. name: 'VTab',
  26. props: makeVTabProps(),
  27. setup(props, _ref) {
  28. let {
  29. slots,
  30. attrs
  31. } = _ref;
  32. const {
  33. textColorClasses: sliderColorClasses,
  34. textColorStyles: sliderColorStyles
  35. } = useTextColor(props, 'sliderColor');
  36. const rootEl = ref();
  37. const sliderEl = ref();
  38. const isHorizontal = computed(() => props.direction === 'horizontal');
  39. const isSelected = computed(() => rootEl.value?.group?.isSelected.value ?? false);
  40. function updateSlider(_ref2) {
  41. let {
  42. value
  43. } = _ref2;
  44. if (value) {
  45. const prevEl = rootEl.value?.$el.parentElement?.querySelector('.v-tab--selected .v-tab__slider');
  46. const nextEl = sliderEl.value;
  47. if (!prevEl || !nextEl) return;
  48. const color = getComputedStyle(prevEl).color;
  49. const prevBox = prevEl.getBoundingClientRect();
  50. const nextBox = nextEl.getBoundingClientRect();
  51. const xy = isHorizontal.value ? 'x' : 'y';
  52. const XY = isHorizontal.value ? 'X' : 'Y';
  53. const rightBottom = isHorizontal.value ? 'right' : 'bottom';
  54. const widthHeight = isHorizontal.value ? 'width' : 'height';
  55. const prevPos = prevBox[xy];
  56. const nextPos = nextBox[xy];
  57. const delta = prevPos > nextPos ? prevBox[rightBottom] - nextBox[rightBottom] : prevBox[xy] - nextBox[xy];
  58. const origin = Math.sign(delta) > 0 ? isHorizontal.value ? 'right' : 'bottom' : Math.sign(delta) < 0 ? isHorizontal.value ? 'left' : 'top' : 'center';
  59. const size = Math.abs(delta) + (Math.sign(delta) < 0 ? prevBox[widthHeight] : nextBox[widthHeight]);
  60. const scale = size / Math.max(prevBox[widthHeight], nextBox[widthHeight]) || 0;
  61. const initialScale = prevBox[widthHeight] / nextBox[widthHeight] || 0;
  62. const sigma = 1.5;
  63. animate(nextEl, {
  64. backgroundColor: [color, 'currentcolor'],
  65. transform: [`translate${XY}(${delta}px) scale${XY}(${initialScale})`, `translate${XY}(${delta / sigma}px) scale${XY}(${(scale - 1) / sigma + 1})`, 'none'],
  66. transformOrigin: Array(3).fill(origin)
  67. }, {
  68. duration: 225,
  69. easing: standardEasing
  70. });
  71. }
  72. }
  73. useRender(() => {
  74. const btnProps = VBtn.filterProps(props);
  75. return _createVNode(VBtn, _mergeProps({
  76. "symbol": VTabsSymbol,
  77. "ref": rootEl,
  78. "class": ['v-tab', props.class],
  79. "style": props.style,
  80. "tabindex": isSelected.value ? 0 : -1,
  81. "role": "tab",
  82. "aria-selected": String(isSelected.value),
  83. "active": false
  84. }, btnProps, attrs, {
  85. "block": props.fixed,
  86. "maxWidth": props.fixed ? 300 : undefined,
  87. "onGroup:selected": updateSlider
  88. }), {
  89. ...slots,
  90. default: () => _createVNode(_Fragment, null, [slots.default?.() ?? props.text, !props.hideSlider && _createVNode("div", {
  91. "ref": sliderEl,
  92. "class": ['v-tab__slider', sliderColorClasses.value],
  93. "style": sliderColorStyles.value
  94. }, null)])
  95. });
  96. });
  97. return forwardRefs({}, rootEl);
  98. }
  99. });
  100. //# sourceMappingURL=VTab.mjs.map