flip-animation 1.0.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.
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # FLIP Animation Library
2
+
3
+ A lightweight JavaScript library for creating smooth FLIP animations with ease.
4
+
5
+ ## What is FLIP Animation?
6
+
7
+ FLIP is an acronym for First, Last, Invert, Play:
8
+ - **First**: Record the initial state of the element
9
+ - **Last**: Record the final state of the element
10
+ - **Invert**: Calculate the difference and apply an inverse transform
11
+ - **Play**: Animate from the inverted state to the final state
12
+
13
+ This technique allows for smooth animations even when elements change position, size, or other properties.
14
+
15
+ ## Installation
16
+
17
+ ### Direct Download
18
+
19
+ Download the `FLIPAnimation.js` file from the repository and include it in your project:
20
+
21
+ ```html
22
+ <script src="FLIPAnimation.js"></script>
23
+ ```
24
+
25
+ ### Using ES Modules
26
+
27
+ For modern JavaScript projects, you can import the library as an ES module:
28
+
29
+ ```javascript
30
+ import { FLIPAnimation, easingFunctions } from './FLIPAnimation.js';
31
+ ```
32
+
33
+ ## API Reference
34
+
35
+ ### FLIPAnimation Class
36
+
37
+ #### Constructor
38
+
39
+ ```javascript
40
+ const flipAnimation = new FLIPAnimation(element, options);
41
+ ```
42
+
43
+ - **element**: The DOM element to animate
44
+ - **options**: Configuration options (optional)
45
+
46
+ #### Options
47
+
48
+ | Option | Type | Default | Description |
49
+ |--------|------|---------|-------------|
50
+ | duration | number | 300 | Animation duration in milliseconds |
51
+ | easing | string or function | 'ease-out' | Easing function or CSS easing string |
52
+ | properties | array | ['transform', 'opacity'] | CSS properties to animate |
53
+ | fill | string | 'forwards' | Animation fill mode |
54
+
55
+ #### Methods
56
+
57
+ - **start()**: Records the initial state of the element
58
+ - **end()**: Calculates the animation and returns the Animation object
59
+
60
+ ### Easing Functions
61
+
62
+ The library includes a variety of built-in easing functions:
63
+
64
+ - linear
65
+ - easeInQuad, easeOutQuad, easeInOutQuad
66
+ - easeInCubic, easeOutCubic, easeInOutCubic
67
+ - easeInQuart, easeOutQuart, easeInOutQuart
68
+ - easeInQuint, easeOutQuint, easeInOutQuint
69
+ - easeInSine, easeOutSine, easeInOutSine
70
+ - easeInExpo, easeOutExpo, easeInOutExpo
71
+ - easeInCirc, easeOutCirc, easeInOutCirc
72
+ - easeInElastic, easeOutElastic, easeInOutElastic
73
+ - easeInBack, easeOutBack, easeInOutBack
74
+ - easeInBounce, easeOutBounce, easeInOutBounce
75
+
76
+ ## Usage Examples
77
+
78
+ ### Basic Example
79
+
80
+ ```javascript
81
+ const element = document.getElementById('myElement');
82
+
83
+ // Create FLIP animation instance
84
+ const flipAnimation = new FLIPAnimation(element, {
85
+ duration: 500,
86
+ easing: 'ease-out',
87
+ properties: ['transform', 'opacity']
88
+ });
89
+
90
+ // Record initial state
91
+ flipAnimation.start();
92
+
93
+ // Change the element's state
94
+ element.classList.toggle('active');
95
+
96
+ // Execute the animation
97
+ const animation = flipAnimation.end();
98
+
99
+ // Listen for animation events
100
+ animation.addEventListener('finish', () => {
101
+ console.log('Animation finished!');
102
+ });
103
+ ```
104
+
105
+ ## Live Examples
106
+
107
+ ### 1. Basic Size and Position Change
108
+
109
+ [View Example](example.html)
110
+
111
+ Demonstrates a simple box that changes size and position with FLIP animation.
112
+
113
+ ### 2. List Sorting Animation
114
+
115
+ [View Example](example-list.html)
116
+
117
+ Shows how to animate list items when sorting them.
118
+
119
+ ### 3. Card Flip Animation
120
+
121
+ [View Example](example-card.html)
122
+
123
+ Demonstrates a 3D card flip effect using FLIP animation.
124
+
125
+ ## Browser Support
126
+
127
+ - Chrome
128
+ - Firefox
129
+ - Safari
130
+ - Edge
131
+
132
+ The library uses the Web Animations API, which is supported in all modern browsers. For older browsers, you may need to include a polyfill.
133
+
134
+ ## Performance Tips
135
+
136
+ - Use `transform` and `opacity` for best performance, as they don't trigger layout
137
+ - Avoid animating properties that cause layout shifts (e.g., width, height, margin)
138
+ - For complex animations, consider using `requestAnimationFrame` for better control
139
+ - When animating multiple elements, use `Promise.all` to wait for all animations to complete
140
+
141
+ ## License
142
+
143
+ MIT License
144
+
145
+ ## Contributing
146
+
147
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,50 @@
1
+ type EasingFunction = (t: number) => number;
2
+ export declare const easingFunctions: {
3
+ linear: (t: number) => number;
4
+ easeInQuad: (t: number) => number;
5
+ easeOutQuad: (t: number) => number;
6
+ easeInOutQuad: (t: number) => number;
7
+ easeInCubic: (t: number) => number;
8
+ easeOutCubic: (t: number) => number;
9
+ easeInOutCubic: (t: number) => number;
10
+ easeInQuart: (t: number) => number;
11
+ easeOutQuart: (t: number) => number;
12
+ easeInOutQuart: (t: number) => number;
13
+ easeInQuint: (t: number) => number;
14
+ easeOutQuint: (t: number) => number;
15
+ easeInOutQuint: (t: number) => number;
16
+ easeInSine: (t: number) => number;
17
+ easeOutSine: (t: number) => number;
18
+ easeInOutSine: (t: number) => number;
19
+ easeInExpo: (t: number) => number;
20
+ easeOutExpo: (t: number) => number;
21
+ easeInOutExpo: (t: number) => number;
22
+ easeInCirc: (t: number) => number;
23
+ easeOutCirc: (t: number) => number;
24
+ easeInOutCirc: (t: number) => number;
25
+ easeInElastic: (t: number) => number;
26
+ easeOutElastic: (t: number) => number;
27
+ easeInOutElastic: (t: number) => number;
28
+ easeInBack: (t: number) => number;
29
+ easeOutBack: (t: number) => number;
30
+ easeInOutBack: (t: number) => number;
31
+ easeInBounce: (t: number) => number;
32
+ easeOutBounce: (t: number) => number;
33
+ easeInOutBounce: (t: number) => number;
34
+ };
35
+ export interface FLIPAnimationOptions {
36
+ duration?: number;
37
+ easing?: string | EasingFunction;
38
+ properties?: string[];
39
+ fill?: FillMode;
40
+ }
41
+ type FillMode = 'none' | 'forwards' | 'backwards' | 'both' | 'auto';
42
+ declare class FLIPAnimation {
43
+ private element;
44
+ private options;
45
+ private initialState;
46
+ constructor(element: HTMLElement, options?: FLIPAnimationOptions);
47
+ start(): void;
48
+ end(): Animation;
49
+ }
50
+ export default FLIPAnimation;
@@ -0,0 +1,194 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ const easingFunctions = {
8
+ // 线性
9
+ linear: (t) => t,
10
+ // 二次方
11
+ easeInQuad: (t) => t * t,
12
+ easeOutQuad: (t) => t * (2 - t),
13
+ easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
14
+ // 三次方
15
+ easeInCubic: (t) => t * t * t,
16
+ easeOutCubic: (t) => --t * t * t + 1,
17
+ easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
18
+ // 四次方
19
+ easeInQuart: (t) => t * t * t * t,
20
+ easeOutQuart: (t) => 1 - --t * t * t * t,
21
+ easeInOutQuart: (t) => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t,
22
+ // 五次方
23
+ easeInQuint: (t) => t * t * t * t * t,
24
+ easeOutQuint: (t) => 1 + --t * t * t * t * t,
25
+ easeInOutQuint: (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t,
26
+ // 正弦
27
+ easeInSine: (t) => 1 - Math.cos(t * Math.PI / 2),
28
+ easeOutSine: (t) => Math.sin(t * Math.PI / 2),
29
+ easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
30
+ // 指数
31
+ easeInExpo: (t) => t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
32
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
33
+ easeInOutExpo: (t) => {
34
+ if (t === 0)
35
+ return 0;
36
+ if (t === 1)
37
+ return 1;
38
+ if (t < 0.5)
39
+ return Math.pow(2, 20 * t - 10) / 2;
40
+ return (2 - Math.pow(2, -20 * t + 10)) / 2;
41
+ },
42
+ // 圆形
43
+ easeInCirc: (t) => 1 - Math.sqrt(1 - t * t),
44
+ easeOutCirc: (t) => Math.sqrt(1 - (t - 1) * (t - 1)),
45
+ easeInOutCirc: (t) => {
46
+ if (t < 0.5)
47
+ return (1 - Math.sqrt(1 - 4 * t * t)) / 2;
48
+ return (Math.sqrt(1 - (-2 * t + 2) * (-2 * t + 2)) + 1) / 2;
49
+ },
50
+ // 弹性
51
+ easeInElastic: (t) => {
52
+ const c4 = 2 * Math.PI / 3;
53
+ return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
54
+ },
55
+ easeOutElastic: (t) => {
56
+ const c4 = 2 * Math.PI / 3;
57
+ return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
58
+ },
59
+ easeInOutElastic: (t) => {
60
+ const c5 = 2 * Math.PI / 4.5;
61
+ if (t === 0)
62
+ return 0;
63
+ if (t === 1)
64
+ return 1;
65
+ if (t < 0.5)
66
+ return -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2;
67
+ return Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5) / 2 + 1;
68
+ },
69
+ // 回退
70
+ easeInBack: (t) => {
71
+ const c1 = 1.70158;
72
+ const c3 = c1 + 1;
73
+ return c3 * t * t * t - c1 * t * t;
74
+ },
75
+ easeOutBack: (t) => {
76
+ const c1 = 1.70158;
77
+ const c3 = c1 + 1;
78
+ return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
79
+ },
80
+ easeInOutBack: (t) => {
81
+ const c1 = 1.70158;
82
+ const c2 = c1 * 1.525;
83
+ if (t < 0.5)
84
+ return Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2) / 2;
85
+ return (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
86
+ },
87
+ // 弹跳
88
+ easeInBounce: (t) => 1 - easingFunctions.easeOutBounce(1 - t),
89
+ easeOutBounce: (t) => {
90
+ const n1 = 7.5625;
91
+ const d1 = 2.75;
92
+ if (t < 1 / d1) {
93
+ return n1 * t * t;
94
+ } else if (t < 2 / d1) {
95
+ return n1 * (t -= 1.5 / d1) * t + 0.75;
96
+ } else if (t < 2.5 / d1) {
97
+ return n1 * (t -= 2.25 / d1) * t + 0.9375;
98
+ } else {
99
+ return n1 * (t -= 2.625 / d1) * t + 0.984375;
100
+ }
101
+ },
102
+ easeInOutBounce: (t) => {
103
+ if (t < 0.5)
104
+ return (1 - easingFunctions.easeOutBounce(1 - 2 * t)) / 2;
105
+ return (1 + easingFunctions.easeOutBounce(2 * t - 1)) / 2;
106
+ }
107
+ };
108
+ class FLIPAnimation {
109
+ constructor(element, options = {}) {
110
+ __publicField(this, "element");
111
+ __publicField(this, "options");
112
+ __publicField(this, "initialState");
113
+ this.element = element;
114
+ this.options = {
115
+ duration: 300,
116
+ easing: "ease-out",
117
+ properties: ["transform", "opacity"],
118
+ fill: "forwards",
119
+ ...options
120
+ };
121
+ this.initialState = null;
122
+ }
123
+ start() {
124
+ this.initialState = {
125
+ rect: this.element.getBoundingClientRect(),
126
+ styles: {}
127
+ };
128
+ const computed = window.getComputedStyle(this.element);
129
+ this.options.properties.forEach((prop) => {
130
+ this.initialState.styles[prop] = computed[prop];
131
+ });
132
+ }
133
+ end() {
134
+ if (!this.initialState) {
135
+ throw new Error("FLIPAnimation: start() must be called before end()");
136
+ }
137
+ const finalRect = this.element.getBoundingClientRect();
138
+ const finalStyles = {};
139
+ const computed = window.getComputedStyle(this.element);
140
+ this.options.properties.forEach((prop) => {
141
+ finalStyles[prop] = computed[prop];
142
+ });
143
+ const invertedStyles = {};
144
+ const needsTransform = this.options.properties.includes("transform");
145
+ if (needsTransform) {
146
+ const deltaX = this.initialState.rect.left - finalRect.left;
147
+ const deltaY = this.initialState.rect.top - finalRect.top;
148
+ const deltaWidth = this.initialState.rect.width / finalRect.width;
149
+ const deltaHeight = this.initialState.rect.height / finalRect.height;
150
+ const invertTransform = `translate(${deltaX}px, ${deltaY}px) scale(${deltaWidth}, ${deltaHeight})`;
151
+ invertedStyles.transform = invertTransform;
152
+ }
153
+ this.options.properties.forEach((prop) => {
154
+ if (prop !== "transform") {
155
+ invertedStyles[prop] = this.initialState.styles[prop];
156
+ }
157
+ });
158
+ Object.assign(this.element.style, invertedStyles);
159
+ this.element.offsetWidth;
160
+ const keyframes = [
161
+ { ...invertedStyles },
162
+ {
163
+ ...needsTransform ? { transform: "none" } : {},
164
+ ...finalStyles
165
+ }
166
+ ];
167
+ const animation = this.element.animate(keyframes, {
168
+ duration: this.options.duration,
169
+ easing: this.options.easing,
170
+ fill: this.options.fill
171
+ });
172
+ return animation;
173
+ }
174
+ }
175
+ (function(root, factory) {
176
+ if (typeof root.define === "function" && root.define.amd) {
177
+ root.define([], factory);
178
+ } else if (typeof root.module === "object" && root.module.exports) {
179
+ const moduleExports = factory();
180
+ root.module.exports = moduleExports;
181
+ root.module.exports.default = moduleExports.FLIPAnimation;
182
+ } else if (root) {
183
+ root.FLIPAnimation = factory().FLIPAnimation;
184
+ }
185
+ })(typeof self !== "undefined" ? self : void 0, function() {
186
+ return {
187
+ FLIPAnimation,
188
+ easingFunctions
189
+ };
190
+ });
191
+ export {
192
+ FLIPAnimation,
193
+ easingFunctions
194
+ };
@@ -0,0 +1 @@
1
+ "use strict";var t=Object.defineProperty,e=(e,n,i)=>(((e,n,i)=>{n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[n]=i})(e,"symbol"!=typeof n?n+"":n,i),i);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>t*(2-t),easeInOutQuad:t=>t<.5?2*t*t:(4-2*t)*t-1,easeInCubic:t=>t*t*t,easeOutCubic:t=>--t*t*t+1,easeInOutCubic:t=>t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1,easeInQuart:t=>t*t*t*t,easeOutQuart:t=>1- --t*t*t*t,easeInOutQuart:t=>t<.5?8*t*t*t*t:1-8*--t*t*t*t,easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>1+--t*t*t*t*t,easeInOutQuint:t=>t<.5?16*t*t*t*t*t:1+16*--t*t*t*t*t,easeInSine:t=>1-Math.cos(t*Math.PI/2),easeOutSine:t=>Math.sin(t*Math.PI/2),easeInOutSine:t=>-(Math.cos(Math.PI*t)-1)/2,easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>0===t?0:1===t?1:t<.5?Math.pow(2,20*t-10)/2:(2-Math.pow(2,-20*t+10))/2,easeInCirc:t=>1-Math.sqrt(1-t*t),easeOutCirc:t=>Math.sqrt(1-(t-1)*(t-1)),easeInOutCirc:t=>t<.5?(1-Math.sqrt(1-4*t*t))/2:(Math.sqrt(1-(-2*t+2)*(-2*t+2))+1)/2,easeInElastic:t=>{const e=2*Math.PI/3;return 0===t?0:1===t?1:-Math.pow(2,10*t-10)*Math.sin((10*t-10.75)*e)},easeOutElastic:t=>{const e=2*Math.PI/3;return 0===t?0:1===t?1:Math.pow(2,-10*t)*Math.sin((10*t-.75)*e)+1},easeInOutElastic:t=>{const e=2*Math.PI/4.5;return 0===t?0:1===t?1:t<.5?-Math.pow(2,20*t-10)*Math.sin((20*t-11.125)*e)/2:Math.pow(2,-20*t+10)*Math.sin((20*t-11.125)*e)/2+1},easeInBack:t=>{const e=1.70158;return 2.70158*t*t*t-e*t*t},easeOutBack:t=>{const e=1.70158;return 1+2.70158*Math.pow(t-1,3)+e*Math.pow(t-1,2)},easeInOutBack:t=>{const e=2.5949095;return t<.5?Math.pow(2*t,2)*(7.189819*t-e)/2:(Math.pow(2*t-2,2)*((e+1)*(2*t-2)+e)+2)/2},easeInBounce:t=>1-n.easeOutBounce(1-t),easeOutBounce:t=>{const e=7.5625,n=2.75;return t<1/n?e*t*t:t<2/n?e*(t-=1.5/n)*t+.75:t<2.5/n?e*(t-=2.25/n)*t+.9375:e*(t-=2.625/n)*t+.984375},easeInOutBounce:t=>t<.5?(1-n.easeOutBounce(1-2*t))/2:(1+n.easeOutBounce(2*t-1))/2};class i{constructor(t,n={}){e(this,"element"),e(this,"options"),e(this,"initialState"),this.element=t,this.options={duration:300,easing:"ease-out",properties:["transform","opacity"],fill:"forwards",...n},this.initialState=null}start(){this.initialState={rect:this.element.getBoundingClientRect(),styles:{}};const t=window.getComputedStyle(this.element);this.options.properties.forEach(e=>{this.initialState.styles[e]=t[e]})}end(){if(!this.initialState)throw new Error("FLIPAnimation: start() must be called before end()");const t=this.element.getBoundingClientRect(),e={},n=window.getComputedStyle(this.element);this.options.properties.forEach(t=>{e[t]=n[t]});const i={},s=this.options.properties.includes("transform");if(s){const e=`translate(${this.initialState.rect.left-t.left}px, ${this.initialState.rect.top-t.top}px) scale(${this.initialState.rect.width/t.width}, ${this.initialState.rect.height/t.height})`;i.transform=e}this.options.properties.forEach(t=>{"transform"!==t&&(i[t]=this.initialState.styles[t])}),Object.assign(this.element.style,i),this.element.offsetWidth;const a=[{...i},{...s?{transform:"none"}:{},...e}];return this.element.animate(a,{duration:this.options.duration,easing:this.options.easing,fill:this.options.fill})}}!function(t,e){if("function"==typeof t.define&&t.define.amd)t.define([],e);else if("object"==typeof t.module&&t.module.exports){const n=e();t.module.exports=n,t.module.exports.default=n.FLIPAnimation}else t&&(t.FLIPAnimation=e().FLIPAnimation)}("undefined"!=typeof self?self:void 0,function(){return{FLIPAnimation:i,easingFunctions:n}}),exports.FLIPAnimation=i,exports.easingFunctions=n;
@@ -0,0 +1 @@
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).FLIPAnimation={})}(this,function(t){"use strict";var e=Object.defineProperty,n=(t,n,i)=>(((t,n,i)=>{n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[n]=i})(t,"symbol"!=typeof n?n+"":n,i),i);const i={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>t*(2-t),easeInOutQuad:t=>t<.5?2*t*t:(4-2*t)*t-1,easeInCubic:t=>t*t*t,easeOutCubic:t=>--t*t*t+1,easeInOutCubic:t=>t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1,easeInQuart:t=>t*t*t*t,easeOutQuart:t=>1- --t*t*t*t,easeInOutQuart:t=>t<.5?8*t*t*t*t:1-8*--t*t*t*t,easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>1+--t*t*t*t*t,easeInOutQuint:t=>t<.5?16*t*t*t*t*t:1+16*--t*t*t*t*t,easeInSine:t=>1-Math.cos(t*Math.PI/2),easeOutSine:t=>Math.sin(t*Math.PI/2),easeInOutSine:t=>-(Math.cos(Math.PI*t)-1)/2,easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>0===t?0:1===t?1:t<.5?Math.pow(2,20*t-10)/2:(2-Math.pow(2,-20*t+10))/2,easeInCirc:t=>1-Math.sqrt(1-t*t),easeOutCirc:t=>Math.sqrt(1-(t-1)*(t-1)),easeInOutCirc:t=>t<.5?(1-Math.sqrt(1-4*t*t))/2:(Math.sqrt(1-(-2*t+2)*(-2*t+2))+1)/2,easeInElastic:t=>{const e=2*Math.PI/3;return 0===t?0:1===t?1:-Math.pow(2,10*t-10)*Math.sin((10*t-10.75)*e)},easeOutElastic:t=>{const e=2*Math.PI/3;return 0===t?0:1===t?1:Math.pow(2,-10*t)*Math.sin((10*t-.75)*e)+1},easeInOutElastic:t=>{const e=2*Math.PI/4.5;return 0===t?0:1===t?1:t<.5?-Math.pow(2,20*t-10)*Math.sin((20*t-11.125)*e)/2:Math.pow(2,-20*t+10)*Math.sin((20*t-11.125)*e)/2+1},easeInBack:t=>{const e=1.70158;return 2.70158*t*t*t-e*t*t},easeOutBack:t=>{const e=1.70158;return 1+2.70158*Math.pow(t-1,3)+e*Math.pow(t-1,2)},easeInOutBack:t=>{const e=2.5949095;return t<.5?Math.pow(2*t,2)*(7.189819*t-e)/2:(Math.pow(2*t-2,2)*((e+1)*(2*t-2)+e)+2)/2},easeInBounce:t=>1-i.easeOutBounce(1-t),easeOutBounce:t=>{const e=7.5625,n=2.75;return t<1/n?e*t*t:t<2/n?e*(t-=1.5/n)*t+.75:t<2.5/n?e*(t-=2.25/n)*t+.9375:e*(t-=2.625/n)*t+.984375},easeInOutBounce:t=>t<.5?(1-i.easeOutBounce(1-2*t))/2:(1+i.easeOutBounce(2*t-1))/2};class s{constructor(t,e={}){n(this,"element"),n(this,"options"),n(this,"initialState"),this.element=t,this.options={duration:300,easing:"ease-out",properties:["transform","opacity"],fill:"forwards",...e},this.initialState=null}start(){this.initialState={rect:this.element.getBoundingClientRect(),styles:{}};const t=window.getComputedStyle(this.element);this.options.properties.forEach(e=>{this.initialState.styles[e]=t[e]})}end(){if(!this.initialState)throw new Error("FLIPAnimation: start() must be called before end()");const t=this.element.getBoundingClientRect(),e={},n=window.getComputedStyle(this.element);this.options.properties.forEach(t=>{e[t]=n[t]});const i={},s=this.options.properties.includes("transform");if(s){const e=`translate(${this.initialState.rect.left-t.left}px, ${this.initialState.rect.top-t.top}px) scale(${this.initialState.rect.width/t.width}, ${this.initialState.rect.height/t.height})`;i.transform=e}this.options.properties.forEach(t=>{"transform"!==t&&(i[t]=this.initialState.styles[t])}),Object.assign(this.element.style,i),this.element.offsetWidth;const a=[{...i},{...s?{transform:"none"}:{},...e}];return this.element.animate(a,{duration:this.options.duration,easing:this.options.easing,fill:this.options.fill})}}!function(t,e){if("function"==typeof t.define&&t.define.amd)t.define([],e);else if("object"==typeof t.module&&t.module.exports){const n=e();t.module.exports=n,t.module.exports.default=n.FLIPAnimation}else t&&(t.FLIPAnimation=e().FLIPAnimation)}("undefined"!=typeof self?self:void 0,function(){return{FLIPAnimation:s,easingFunctions:i}}),t.FLIPAnimation=s,t.easingFunctions=i,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1,2 @@
1
+ export { default as FLIPAnimation, easingFunctions } from './FLIPAnimation';
2
+ export type { FLIPAnimationOptions } from './FLIPAnimation';
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "flip-animation",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight FLIP animation library for smooth transitions",
5
+ "type": "module",
6
+ "main": "./dist/flip-animation.js",
7
+ "module": "./dist/flip-animation.es.js",
8
+ "types": "./dist/index.d.ts",
9
+ "scripts": {
10
+ "dev": "vite",
11
+ "build": "tsc && vite build",
12
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
13
+ "preview": "vite preview",
14
+ "test": "vitest"
15
+ },
16
+ "keywords": [
17
+ "animation",
18
+ "flip",
19
+ "transition",
20
+ "javascript",
21
+ "typescript"
22
+ ],
23
+ "author": "",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": ""
28
+ },
29
+ "homepage": "",
30
+ "dependencies": {},
31
+ "devDependencies": {
32
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
33
+ "@typescript-eslint/parser": "^6.0.0",
34
+ "eslint": "^8.45.0",
35
+ "jsdom": "^28.1.0",
36
+ "terser": "^5.46.0",
37
+ "typescript": "^5.0.2",
38
+ "vite": "^4.4.5",
39
+ "vitest": "^4.1.0"
40
+ }
41
+ }