PageSourceSearch

https://tempoco.cc/javascripts/shared-components/CollapseTransition.js

js tempoco.cc collected 2026-10-04 18:34:14 UTC 6,820 bytes, 239 lines download raw bytes

1// This code come from https://github.com/BinarCode/vue2-transitions
2// Updated for Vue 3 compatibility
3
4const BaseTransitionMixin = {
5  inheritAttrs: false,
6  props: {
7    /**
8     * Transition duration. Number for specifying the same duration for enter/leave transitions
9     * Object style {enter: 300, leave: 300} for specifying explicit durations for enter/leave
10     */
11    duration: {
12      type: [Number, Object],
13      default: 200,
14    },
15    /**
16     * Transition delay. Number for specifying the same delay for enter/leave transitions
17     * Object style {enter: 300, leave: 300} for specifying explicit durations for enter/leave
18     */
19    delay: {
20      type: [Number, Object],
21      default: 0,
22    },
23    /**
24     * Whether the component should be a `transition-group` component.
25     */
26    group: Boolean,
27    /**
28     * Transition tag, in case the component is a `transition-group`
29     */
30    tag: {
31      type: String,
32      default: 'span',
33    },
34    /**
35     *  Transform origin property https://tympanus.net/codrops/css_reference/transform-origin/.
36     *  Can be specified with styles as well but it's shorter with this prop
37     */
38    origin: {
39      type: String,
40      default: '',
41    },
42    /**
43     * Element styles that are applied during transition. These styles are applied on @beforeEnter and @beforeLeave hooks
44     */
45    styles: {
46      type: Object,
47      default: () => ({
48        animationFillMode: 'both',
49        animationTimingFunction: 'ease-out',
50      }),
51    },
52  },
53  emits: [
54    'before-enter',
55    'after-enter',
56    'before-leave',
57    'leave',
58    'after-leave',
59  ],
60  computed: {
61    componentType() {
62      return this.group ? 'transition-group' : 'transition'
63    },
64    hooks() {
65      // In Vue 3, $listeners is merged into $attrs
66      return {
67        ...this.$attrs,
68        beforeEnter: this.beforeEnter,
69        afterEnter: (el) => {
70          this.cleanUpStyles(el)
71          this.$emit('after-enter', el)
72        },
73        beforeLeave: this.beforeLeave,
74        leave: this.leave,
75        afterLeave: (el) => {
76          this.cleanUpStyles(el)
77          this.$emit('after-leave', el)
78        },
79      }
80    },
81  },
82  methods: {
83    beforeEnter(el) {
84      const enterDuration = this.duration.enter
85        ? this.duration.enter
86        : this.duration
87      el.style.animationDuration = `${enterDuration}ms`
88
89      const enterDelay = this.delay.enter ? this.delay.enter : this.delay
90      el.style.animationDelay = `${enterDelay}ms`
91
92      this.setStyles(el)
93      this.$emit('before-enter', el)
94    },
95    cleanUpStyles(el) {
96      Object.keys(this.styles).forEach((key) => {
97        const styleValue = this.styles[key]
98        if (styleValue) {
99          el.style[key] = ''
100        }
101      })
102      el.style.animationDuration = ''
103      el.style.animationDelay = ''
104    },
105    beforeLeave(el) {
106      const leaveDuration = this.duration.leave
107        ? this.duration.leave
108        : this.duration
109      el.style.animationDuration = `${leaveDuration}ms`
110
111      const leaveDelay = this.delay.leave ? this.delay.leave : this.delay
112      el.style.animationDelay = `${leaveDelay}ms`
113
114      this.setStyles(el)
115      this.$emit('before-leave', el)
116    },
117    leave(el, done) {
118      this.setAbsolutePosition(el)
119      this.$emit('leave', el, done)
120    },
121    setStyles(el) {
122      this.setTransformOrigin(el)
123      Object.keys(this.styles).forEach((key) => {
124        const styleValue = this.styles[key]
125        if (styleValue) {
126          el.style[key] = styleValue
127        }
128      })
129    },
130    setAbsolutePosition(el) {
131      if (this.group) {
132        el.style.position = 'absolute'
133      }
134      return this
135    },
136    setTransformOrigin(el) {
137      if (this.origin) {
138        el.style.transformOrigin = this.origin
139      }
140      return this
141    },
142  },
143}
144
145export default {
146  name: 'collapse-transition',
147  mixins: [BaseTransitionMixin],
148  methods: {
149    transitionStyle(duration = 300) {
150      const durationInSeconds = duration / 1000
151      const style = `${durationInSeconds}s height ease-in-out, ${durationInSeconds}s padding-top ease-in-out, ${durationInSeconds}s padding-bottom ease-in-out`
152      return style
153    },
154    beforeEnter(el) {
155      const enterDuration = this.duration.enter
156        ? this.duration.enter
157        : this.duration
158      el.style.transition = this.transitionStyle(enterDuration)
159      if (!el.dataset) el.dataset = {}
160
161      el.dataset.oldPaddingTop = el.style.paddingTop
162      el.dataset.oldPaddingBottom = el.style.paddingBottom
163
164      el.style.height = '0'
165      el.style.paddingTop = 0
166      el.style.paddingBottom = 0
167      this.setStyles(el)
168    },
169
170    enter(el) {
171      el.dataset.oldOverflow = el.style.overflow
172      if (el.scrollHeight !== 0) {
173        el.style.height = `${el.scrollHeight}px`
174        el.style.paddingTop = el.dataset.oldPaddingTop
175        el.style.paddingBottom = el.dataset.oldPaddingBottom
176      } else {
177        el.style.height = ''
178        el.style.paddingTop = el.dataset.oldPaddingTop
179        el.style.paddingBottom = el.dataset.oldPaddingBottom
180      }
181
182      el.style.overflow = 'hidden'
183    },
184
185    afterEnter(el) {
186      // for safari: remove class then reset height is necessary
187      el.style.transition = ''
188      el.style.height = ''
189      el.style.overflow = el.dataset.oldOverflow
190    },
191
192    beforeLeave(el) {
193      if (!el.dataset) el.dataset = {}
194      el.dataset.oldPaddingTop = el.style.paddingTop
195      el.dataset.oldPaddingBottom = el.style.paddingBottom
196      el.dataset.oldOverflow = el.style.overflow
197
198      el.style.height = `${el.scrollHeight}px`
199      el.style.overflow = 'hidden'
200      this.setStyles(el)
201    },
202
203    leave(el) {
204      const leaveDuration = this.duration.leave
205        ? this.duration.leave
206        : this.duration
207      if (el.scrollHeight !== 0) {
208        // for safari: add class after set height, or it will jump to zero height suddenly, weired
209        el.style.transition = this.transitionStyle(leaveDuration)
210        el.style.height = 0
211        el.style.paddingTop = 0
212        el.style.paddingBottom = 0
213      }
214      // necessary for transition-group
215      this.setAbsolutePosition(el)
216    },
217
218    afterLeave(el) {
219      el.style.transition = ''
220      el.style.height = ''
221      el.style.overflow = el.dataset.oldOverflow
222      el.style.paddingTop = el.dataset.oldPaddingTop
223      el.style.paddingBottom = el.dataset.oldPaddingBottom
224    },
225  },
226  template: `
227    <component :is="componentType"
228            :tag="tag"
229            v-bind="$attrs"
230            @before-enter="beforeEnter"
231            @after-enter="afterEnter"
232            @enter="enter"
233            @before-leave="beforeLeave"
234            @leave="leave"
235            @after-leave="afterLeave"
236            move-class="collapse-move">
237      <slot></slot>
238    </component>`,
239}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.