Sfoglia il codice sorgente

feat: add the CollapseTransition component to achieve the collapse transition effect

nian 1 mese fa
parent
commit
ced8145287
1 ha cambiato i file con 81 aggiunte e 0 eliminazioni
  1. 81 0
      src/components/CollapseTransition.vue

+ 81 - 0
src/components/CollapseTransition.vue

@@ -0,0 +1,81 @@
+<script setup lang="ts">
+import type { CSSProperties, TransitionProps } from 'vue'
+
+interface CollapseTransitionProps extends TransitionProps {
+  displayDirective?: 'if' | 'show'
+  display?: boolean
+  direction?: 'vertical' | 'horizontal'
+  transitionDuration?: number
+  containerClass?: string
+  containerStyle?: CSSProperties
+  renderContent?: boolean
+  contentTag?: string
+  contentClass?: string
+  contentStyle?: CSSProperties
+}
+
+const {
+  direction = 'vertical',
+  type = 'transition',
+  displayDirective = 'if',
+  display,
+  transitionDuration,
+  contentTag = 'div',
+  renderContent = true,
+  contentClass,
+  contentStyle,
+  containerClass,
+  containerStyle,
+} = defineProps<CollapseTransitionProps>()
+
+const BASE_CLASSES = {
+  vertical: {
+    activeClass: 'transition-[grid-template-columns]',
+    fromClass: 'grid-cols-[0fr]',
+    toClass: 'grid-cols-[1fr]',
+    contentClass: 'min-w-0',
+  },
+  horizontal: {
+    activeClass: 'transition-[grid-template-rows]',
+    fromClass: 'grid-rows-[0fr]',
+    toClass: 'grid-rows-[1fr]',
+    contentClass: 'min-h-0',
+  },
+}
+</script>
+<template>
+  <Transition
+    :type="type"
+    :enter-active-class="BASE_CLASSES[direction].activeClass"
+    :leave-active-class="BASE_CLASSES[direction].activeClass"
+    :enter-from-class="BASE_CLASSES[direction].fromClass"
+    :leave-to-class="BASE_CLASSES[direction].fromClass"
+    :enter-to-class="BASE_CLASSES[direction].toClass"
+    :leave-from-class="BASE_CLASSES[direction].toClass"
+    v-bind="$attrs"
+  >
+    <div
+      v-if="displayDirective === 'if' ? display : true"
+      v-show="displayDirective === 'show' ? display : true"
+      class="grid overflow-hidden"
+      :class="containerClass"
+      :style="[
+        typeof transitionDuration === 'number' &&
+          transitionDuration > 0 && {
+            '--default-transition-duration': `${transitionDuration}ms`,
+          },
+        containerStyle,
+      ]"
+    >
+      <component
+        v-if="renderContent"
+        :is="contentTag"
+        :class="[BASE_CLASSES[direction].contentClass, contentClass]"
+        :style="contentStyle"
+      >
+        <slot />
+      </component>
+      <slot v-else />
+    </div>
+  </Transition>
+</template>