@veltra/utils 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -15,8 +15,13 @@ declare class ExpandTransition {
|
|
|
15
15
|
beforeLeave(el: HTMLElement): void;
|
|
16
16
|
leave(el: HTMLElement): void;
|
|
17
17
|
afterLeave(el: HTMLElement): void;
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* 展开动画;`onEnd` 在动画落定(含无需动画直接落定)后调用,
|
|
20
|
+
* 被新的动画打断时不调用
|
|
21
|
+
*/
|
|
22
|
+
expand(el: HTMLElement, onEnd?: () => void): void;
|
|
23
|
+
/** 收起动画;`onEnd` 语义同 `expand` */
|
|
24
|
+
collapse(el: HTMLElement, onEnd?: () => void): void;
|
|
20
25
|
setExpanded(el: HTMLElement, expanded: boolean): void;
|
|
21
26
|
private animate;
|
|
22
27
|
private resetTransitionStyles;
|
|
@@ -69,11 +69,16 @@ var ExpandTransition = class {
|
|
|
69
69
|
afterLeave(el) {
|
|
70
70
|
this.resetTransitionStyles(el);
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
/**
|
|
73
|
+
* 展开动画;`onEnd` 在动画落定(含无需动画直接落定)后调用,
|
|
74
|
+
* 被新的动画打断时不调用
|
|
75
|
+
*/
|
|
76
|
+
expand(el, onEnd) {
|
|
77
|
+
this.animate(el, true, onEnd);
|
|
74
78
|
}
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
/** 收起动画;`onEnd` 语义同 `expand` */
|
|
80
|
+
collapse(el, onEnd) {
|
|
81
|
+
this.animate(el, false, onEnd);
|
|
77
82
|
}
|
|
78
83
|
setExpanded(el, expanded) {
|
|
79
84
|
this.cancel(el);
|
|
@@ -81,13 +86,14 @@ var ExpandTransition = class {
|
|
|
81
86
|
el.style.overflow = "hidden";
|
|
82
87
|
el.style.height = expanded ? "auto" : "0px";
|
|
83
88
|
}
|
|
84
|
-
animate(el, expanded) {
|
|
89
|
+
animate(el, expanded, onEnd) {
|
|
85
90
|
this.cancel(el);
|
|
86
91
|
const startHeight = el.offsetHeight;
|
|
87
92
|
const endHeight = expanded ? el.scrollHeight : 0;
|
|
88
93
|
const { paddingTop, paddingBottom } = readVerticalPadding(el);
|
|
89
94
|
if (startHeight === endHeight) {
|
|
90
95
|
this.setExpanded(el, expanded);
|
|
96
|
+
onEnd?.();
|
|
91
97
|
return;
|
|
92
98
|
}
|
|
93
99
|
setStyles(el, {
|
|
@@ -106,19 +112,20 @@ var ExpandTransition = class {
|
|
|
106
112
|
paddingBottom: expanded ? paddingBottom : 0
|
|
107
113
|
});
|
|
108
114
|
const cleanup = () => {
|
|
109
|
-
el.removeEventListener("transitionend",
|
|
110
|
-
el.removeEventListener("transitioncancel",
|
|
115
|
+
el.removeEventListener("transitionend", onEndHandler);
|
|
116
|
+
el.removeEventListener("transitioncancel", onEndHandler);
|
|
111
117
|
this.cleanupMap.delete(el);
|
|
112
118
|
};
|
|
113
|
-
const
|
|
119
|
+
const onEndHandler = (e) => {
|
|
114
120
|
if (e.target !== el || e.propertyName !== "height") return;
|
|
115
121
|
cleanup();
|
|
116
122
|
this.resetTemporaryStyles(el);
|
|
117
123
|
el.style.overflow = "hidden";
|
|
118
124
|
el.style.height = expanded ? "auto" : "0px";
|
|
125
|
+
onEnd?.();
|
|
119
126
|
};
|
|
120
|
-
el.addEventListener("transitionend",
|
|
121
|
-
el.addEventListener("transitioncancel",
|
|
127
|
+
el.addEventListener("transitionend", onEndHandler);
|
|
128
|
+
el.addEventListener("transitioncancel", onEndHandler);
|
|
122
129
|
this.cleanupMap.set(el, cleanup);
|
|
123
130
|
}
|
|
124
131
|
resetTransitionStyles(el) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expand-transition.js","names":[],"sources":["../../src/dom/expand-transition.ts"],"sourcesContent":["import { removeStyles, setStyles } from './style'\n\nexport interface ExpandTransitionOptions {\n transition?: string\n enterTransition?: string\n leaveTransition?: string\n opacity?: boolean\n}\n\nfunction readVerticalPadding(el: HTMLElement) {\n const { paddingTop, paddingBottom } = getComputedStyle(el)\n return { paddingTop, paddingBottom }\n}\n\nfunction getTransition(options: ExpandTransitionOptions, type: 'enter' | 'leave') {\n return (\n (type === 'enter' ? options.enterTransition : options.leaveTransition) ??\n options.transition ??\n 'height 0.25s cubic-bezier(0.4, 0, 0.2, 1)'\n )\n}\n\nexport class ExpandTransition {\n private cleanupMap = new Map<HTMLElement, () => void>()\n\n constructor(private options: ExpandTransitionOptions = {}) {}\n\n cancel(el: HTMLElement) {\n this.cleanupMap.get(el)?.()\n this.cleanupMap.delete(el)\n }\n\n enter(el: HTMLElement) {\n const height = el.scrollHeight\n const { paddingTop, paddingBottom } = readVerticalPadding(el)\n\n setStyles(el, {\n boxSizing: 'border-box',\n height: 0,\n paddingTop: 0,\n paddingBottom: 0,\n overflow: 'hidden',\n transition: getTransition(this.options, 'enter'),\n willChange: this.options.opacity ? 'height, opacity' : 'height'\n })\n\n if (this.options.opacity) {\n el.style.opacity = '0'\n }\n\n void el.offsetHeight\n\n setStyles(el, { height: `${height}px`, paddingTop, paddingBottom })\n\n if (this.options.opacity) {\n el.style.opacity = '1'\n }\n }\n\n afterEnter(el: HTMLElement) {\n this.resetTransitionStyles(el)\n }\n\n beforeLeave(el: HTMLElement) {\n const { paddingTop, paddingBottom } = readVerticalPadding(el)\n\n setStyles(el, {\n boxSizing: 'border-box',\n height: `${el.scrollHeight}px`,\n paddingTop,\n paddingBottom,\n overflow: 'hidden',\n transition: getTransition(this.options, 'leave'),\n willChange: this.options.opacity ? 'height, opacity' : 'height'\n })\n\n if (this.options.opacity) {\n el.style.opacity = '1'\n }\n }\n\n leave(el: HTMLElement) {\n void el.offsetHeight\n\n setStyles(el, { height: 0, paddingTop: 0, paddingBottom: 0 })\n\n if (this.options.opacity) {\n el.style.opacity = '0'\n }\n }\n\n afterLeave(el: HTMLElement) {\n this.resetTransitionStyles(el)\n }\n\n expand(el: HTMLElement) {\n this.animate(el, true)\n }\n\n collapse(el: HTMLElement) {\n this.animate(el, false)\n }\n\n setExpanded(el: HTMLElement, expanded: boolean) {\n this.cancel(el)\n this.resetTemporaryStyles(el)\n el.style.overflow = 'hidden'\n el.style.height = expanded ? 'auto' : '0px'\n }\n\n private animate(el: HTMLElement, expanded: boolean) {\n this.cancel(el)\n\n const startHeight = el.offsetHeight\n const endHeight = expanded ? el.scrollHeight : 0\n const { paddingTop, paddingBottom } = readVerticalPadding(el)\n\n if (startHeight === endHeight) {\n this.setExpanded(el, expanded)\n return\n }\n\n setStyles(el, {\n boxSizing: 'border-box',\n height: `${startHeight}px`,\n paddingTop,\n paddingBottom,\n overflow: 'hidden',\n transition: getTransition(this.options, expanded ? 'enter' : 'leave'),\n willChange: 'height'\n })\n\n void el.offsetHeight\n\n setStyles(el, {\n height: `${endHeight}px`,\n paddingTop: expanded ? paddingTop : 0,\n paddingBottom: expanded ? paddingBottom : 0\n })\n\n const cleanup = () => {\n el.removeEventListener('transitionend',
|
|
1
|
+
{"version":3,"file":"expand-transition.js","names":[],"sources":["../../src/dom/expand-transition.ts"],"sourcesContent":["import { removeStyles, setStyles } from './style'\n\nexport interface ExpandTransitionOptions {\n transition?: string\n enterTransition?: string\n leaveTransition?: string\n opacity?: boolean\n}\n\nfunction readVerticalPadding(el: HTMLElement) {\n const { paddingTop, paddingBottom } = getComputedStyle(el)\n return { paddingTop, paddingBottom }\n}\n\nfunction getTransition(options: ExpandTransitionOptions, type: 'enter' | 'leave') {\n return (\n (type === 'enter' ? options.enterTransition : options.leaveTransition) ??\n options.transition ??\n 'height 0.25s cubic-bezier(0.4, 0, 0.2, 1)'\n )\n}\n\nexport class ExpandTransition {\n private cleanupMap = new Map<HTMLElement, () => void>()\n\n constructor(private options: ExpandTransitionOptions = {}) {}\n\n cancel(el: HTMLElement) {\n this.cleanupMap.get(el)?.()\n this.cleanupMap.delete(el)\n }\n\n enter(el: HTMLElement) {\n const height = el.scrollHeight\n const { paddingTop, paddingBottom } = readVerticalPadding(el)\n\n setStyles(el, {\n boxSizing: 'border-box',\n height: 0,\n paddingTop: 0,\n paddingBottom: 0,\n overflow: 'hidden',\n transition: getTransition(this.options, 'enter'),\n willChange: this.options.opacity ? 'height, opacity' : 'height'\n })\n\n if (this.options.opacity) {\n el.style.opacity = '0'\n }\n\n void el.offsetHeight\n\n setStyles(el, { height: `${height}px`, paddingTop, paddingBottom })\n\n if (this.options.opacity) {\n el.style.opacity = '1'\n }\n }\n\n afterEnter(el: HTMLElement) {\n this.resetTransitionStyles(el)\n }\n\n beforeLeave(el: HTMLElement) {\n const { paddingTop, paddingBottom } = readVerticalPadding(el)\n\n setStyles(el, {\n boxSizing: 'border-box',\n height: `${el.scrollHeight}px`,\n paddingTop,\n paddingBottom,\n overflow: 'hidden',\n transition: getTransition(this.options, 'leave'),\n willChange: this.options.opacity ? 'height, opacity' : 'height'\n })\n\n if (this.options.opacity) {\n el.style.opacity = '1'\n }\n }\n\n leave(el: HTMLElement) {\n void el.offsetHeight\n\n setStyles(el, { height: 0, paddingTop: 0, paddingBottom: 0 })\n\n if (this.options.opacity) {\n el.style.opacity = '0'\n }\n }\n\n afterLeave(el: HTMLElement) {\n this.resetTransitionStyles(el)\n }\n\n /**\n * 展开动画;`onEnd` 在动画落定(含无需动画直接落定)后调用,\n * 被新的动画打断时不调用\n */\n expand(el: HTMLElement, onEnd?: () => void) {\n this.animate(el, true, onEnd)\n }\n\n /** 收起动画;`onEnd` 语义同 `expand` */\n collapse(el: HTMLElement, onEnd?: () => void) {\n this.animate(el, false, onEnd)\n }\n\n setExpanded(el: HTMLElement, expanded: boolean) {\n this.cancel(el)\n this.resetTemporaryStyles(el)\n el.style.overflow = 'hidden'\n el.style.height = expanded ? 'auto' : '0px'\n }\n\n private animate(el: HTMLElement, expanded: boolean, onEnd?: () => void) {\n this.cancel(el)\n\n const startHeight = el.offsetHeight\n const endHeight = expanded ? el.scrollHeight : 0\n const { paddingTop, paddingBottom } = readVerticalPadding(el)\n\n if (startHeight === endHeight) {\n this.setExpanded(el, expanded)\n onEnd?.()\n return\n }\n\n setStyles(el, {\n boxSizing: 'border-box',\n height: `${startHeight}px`,\n paddingTop,\n paddingBottom,\n overflow: 'hidden',\n transition: getTransition(this.options, expanded ? 'enter' : 'leave'),\n willChange: 'height'\n })\n\n void el.offsetHeight\n\n setStyles(el, {\n height: `${endHeight}px`,\n paddingTop: expanded ? paddingTop : 0,\n paddingBottom: expanded ? paddingBottom : 0\n })\n\n const cleanup = () => {\n el.removeEventListener('transitionend', onEndHandler)\n el.removeEventListener('transitioncancel', onEndHandler)\n this.cleanupMap.delete(el)\n }\n\n const onEndHandler = (e: TransitionEvent) => {\n if (e.target !== el || e.propertyName !== 'height') return\n cleanup()\n this.resetTemporaryStyles(el)\n el.style.overflow = 'hidden'\n el.style.height = expanded ? 'auto' : '0px'\n onEnd?.()\n }\n\n el.addEventListener('transitionend', onEndHandler)\n el.addEventListener('transitioncancel', onEndHandler)\n this.cleanupMap.set(el, cleanup)\n }\n\n private resetTransitionStyles(el: HTMLElement) {\n removeStyles(el, [\n 'box-sizing',\n 'height',\n 'padding-top',\n 'padding-bottom',\n 'overflow',\n 'transition',\n 'opacity',\n 'will-change'\n ])\n }\n\n private resetTemporaryStyles(el: HTMLElement) {\n removeStyles(el, [\n 'box-sizing',\n 'padding-top',\n 'padding-bottom',\n 'transition',\n 'opacity',\n 'will-change'\n ])\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
2
|
|
|
3
3
|
import { ExpandTransition } from '../expand-transition'
|
|
4
4
|
|
|
@@ -96,4 +96,54 @@ describe('ExpandTransition', () => {
|
|
|
96
96
|
transition.cancel(el)
|
|
97
97
|
}
|
|
98
98
|
})
|
|
99
|
+
|
|
100
|
+
it('invokes onEnd after the transition settles', () => {
|
|
101
|
+
const el = createPanel()
|
|
102
|
+
const transition = new ExpandTransition({ transition: 'height 0.25s ease' })
|
|
103
|
+
const onEnd = vi.fn()
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
transition.collapse(el, onEnd)
|
|
107
|
+
expect(onEnd).not.toHaveBeenCalled()
|
|
108
|
+
|
|
109
|
+
fireHeightTransitionEnd(el)
|
|
110
|
+
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
111
|
+
} finally {
|
|
112
|
+
el.remove()
|
|
113
|
+
transition.cancel(el)
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('does not invoke onEnd when interrupted by a new animation', () => {
|
|
118
|
+
const el = createPanel()
|
|
119
|
+
const transition = new ExpandTransition({ transition: 'height 0.25s ease' })
|
|
120
|
+
const onEnd = vi.fn()
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
transition.collapse(el, onEnd)
|
|
124
|
+
// 新动画打断旧动画:旧 onEnd 不应再触发
|
|
125
|
+
transition.expand(el)
|
|
126
|
+
fireHeightTransitionEnd(el)
|
|
127
|
+
expect(onEnd).not.toHaveBeenCalled()
|
|
128
|
+
} finally {
|
|
129
|
+
el.remove()
|
|
130
|
+
transition.cancel(el)
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('invokes onEnd immediately when no animation is needed', () => {
|
|
135
|
+
const el = document.createElement('div')
|
|
136
|
+
document.body.appendChild(el)
|
|
137
|
+
const transition = new ExpandTransition({ transition: 'height 0.25s ease' })
|
|
138
|
+
const onEnd = vi.fn()
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
// 高度已为 0(happy-dom 无布局),收起无需动画,onEnd 同步调用
|
|
142
|
+
transition.collapse(el, onEnd)
|
|
143
|
+
expect(onEnd).toHaveBeenCalledTimes(1)
|
|
144
|
+
} finally {
|
|
145
|
+
el.remove()
|
|
146
|
+
transition.cancel(el)
|
|
147
|
+
}
|
|
148
|
+
})
|
|
99
149
|
})
|
|
@@ -93,12 +93,17 @@ export class ExpandTransition {
|
|
|
93
93
|
this.resetTransitionStyles(el)
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
/**
|
|
97
|
+
* 展开动画;`onEnd` 在动画落定(含无需动画直接落定)后调用,
|
|
98
|
+
* 被新的动画打断时不调用
|
|
99
|
+
*/
|
|
100
|
+
expand(el: HTMLElement, onEnd?: () => void) {
|
|
101
|
+
this.animate(el, true, onEnd)
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
/** 收起动画;`onEnd` 语义同 `expand` */
|
|
105
|
+
collapse(el: HTMLElement, onEnd?: () => void) {
|
|
106
|
+
this.animate(el, false, onEnd)
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
setExpanded(el: HTMLElement, expanded: boolean) {
|
|
@@ -108,7 +113,7 @@ export class ExpandTransition {
|
|
|
108
113
|
el.style.height = expanded ? 'auto' : '0px'
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
private animate(el: HTMLElement, expanded: boolean) {
|
|
116
|
+
private animate(el: HTMLElement, expanded: boolean, onEnd?: () => void) {
|
|
112
117
|
this.cancel(el)
|
|
113
118
|
|
|
114
119
|
const startHeight = el.offsetHeight
|
|
@@ -117,6 +122,7 @@ export class ExpandTransition {
|
|
|
117
122
|
|
|
118
123
|
if (startHeight === endHeight) {
|
|
119
124
|
this.setExpanded(el, expanded)
|
|
125
|
+
onEnd?.()
|
|
120
126
|
return
|
|
121
127
|
}
|
|
122
128
|
|
|
@@ -139,21 +145,22 @@ export class ExpandTransition {
|
|
|
139
145
|
})
|
|
140
146
|
|
|
141
147
|
const cleanup = () => {
|
|
142
|
-
el.removeEventListener('transitionend',
|
|
143
|
-
el.removeEventListener('transitioncancel',
|
|
148
|
+
el.removeEventListener('transitionend', onEndHandler)
|
|
149
|
+
el.removeEventListener('transitioncancel', onEndHandler)
|
|
144
150
|
this.cleanupMap.delete(el)
|
|
145
151
|
}
|
|
146
152
|
|
|
147
|
-
const
|
|
153
|
+
const onEndHandler = (e: TransitionEvent) => {
|
|
148
154
|
if (e.target !== el || e.propertyName !== 'height') return
|
|
149
155
|
cleanup()
|
|
150
156
|
this.resetTemporaryStyles(el)
|
|
151
157
|
el.style.overflow = 'hidden'
|
|
152
158
|
el.style.height = expanded ? 'auto' : '0px'
|
|
159
|
+
onEnd?.()
|
|
153
160
|
}
|
|
154
161
|
|
|
155
|
-
el.addEventListener('transitionend',
|
|
156
|
-
el.addEventListener('transitioncancel',
|
|
162
|
+
el.addEventListener('transitionend', onEndHandler)
|
|
163
|
+
el.addEventListener('transitioncancel', onEndHandler)
|
|
157
164
|
this.cleanupMap.set(el, cleanup)
|
|
158
165
|
}
|
|
159
166
|
|