ExpandTransition.ts
2.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/**
* Makes the first character of a string uppercase
*/
export function upperFirst(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
interface HTMLExpandElement extends HTMLElement {
_parent?: (Node & ParentNode & HTMLElement) | null;
_initialStyle: {
transition: string;
overflow: string | null;
height?: string | null;
width?: string | null;
};
}
export default function (expandedParentClass = '', x = false) {
const sizeProperty = x ? 'width' : ('height' as 'width' | 'height');
const offsetProperty = `offset${upperFirst(sizeProperty)}` as 'offsetHeight' | 'offsetWidth';
return {
beforeEnter(el: HTMLExpandElement) {
el._parent = el.parentNode as (Node & ParentNode & HTMLElement) | null;
el._initialStyle = {
transition: el.style.transition,
overflow: el.style.overflow,
[sizeProperty]: el.style[sizeProperty],
};
},
enter(el: HTMLExpandElement) {
const initialStyle = el._initialStyle;
el.style.setProperty('transition', 'none', 'important');
el.style.overflow = 'hidden';
// const offset = `${el[offsetProperty]}px`;
// el.style[sizeProperty] = '0';
void el.offsetHeight; // force reflow
el.style.transition = initialStyle.transition;
if (expandedParentClass && el._parent) {
el._parent.classList.add(expandedParentClass);
}
requestAnimationFrame(() => {
// el.style[sizeProperty] = offset;
});
},
afterEnter: resetStyles,
enterCancelled: resetStyles,
leave(el: HTMLExpandElement) {
el._initialStyle = {
transition: '',
overflow: el.style.overflow,
[sizeProperty]: el.style[sizeProperty],
};
el.style.overflow = 'hidden';
el.style[sizeProperty] = `${el[offsetProperty]}px`;
/* eslint-disable-next-line */
void el.offsetHeight; // force reflow
requestAnimationFrame(() => (el.style[sizeProperty] = '0'));
},
afterLeave,
leaveCancelled: afterLeave,
};
function afterLeave(el: HTMLExpandElement) {
if (expandedParentClass && el._parent) {
el._parent.classList.remove(expandedParentClass);
}
resetStyles(el);
}
function resetStyles(el: HTMLExpandElement) {
const size = el._initialStyle[sizeProperty];
el.style.overflow = el._initialStyle.overflow!;
if (size != null) el.style[sizeProperty] = size;
Reflect.deleteProperty(el, '_initialStyle');
}
}