@lytjs/plugin-animation 6.4.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/dist/index.js ADDED
@@ -0,0 +1,781 @@
1
+ // src/index.ts
2
+ import { definePlugin } from "@lytjs/core";
3
+ import { signal } from "@lytjs/reactivity";
4
+
5
+ // src/gpu-acceleration.ts
6
+ var DEFAULT_GPU_OPTIONS = {
7
+ enable3D: true,
8
+ willChange: "transform",
9
+ force3D: false,
10
+ compositorThreshold: 1e-3
11
+ };
12
+ function to3DTransform(transform) {
13
+ return transform.replace(/translateX\(([^)]+)\)/g, "translate3d($1, 0, 0)").replace(/translateY\(([^)]+)\)/g, "translate3d(0, $1, 0)").replace(/translate\(([^,]+),\s*([^)]+)\)/g, "translate3d($1, $2, 0)").replace(/scale\(([^)]+)\)/g, "scale3d($1, $1, 1)").replace(/scale\(([^,]+),\s*([^)]+)\)/g, "scale3d($1, $2, 1)");
14
+ }
15
+ function canUseGPU(element) {
16
+ const el = element;
17
+ if (typeof window === "undefined") return false;
18
+ const noGPU = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
19
+ navigator.userAgent
20
+ );
21
+ if (noGPU) {
22
+ const hasGPU = el.style.transform !== void 0;
23
+ return hasGPU;
24
+ }
25
+ return true;
26
+ }
27
+ function enableGPUAcceleration(element, options = DEFAULT_GPU_OPTIONS) {
28
+ const { willChange = "transform" } = options;
29
+ element.style.willChange = willChange;
30
+ element.style.backfaceVisibility = "hidden";
31
+ element.style.perspective = "1000px";
32
+ }
33
+ function disableGPUAcceleration(element) {
34
+ element.style.willChange = "auto";
35
+ element.style.backfaceVisibility = "";
36
+ element.style.perspective = "";
37
+ }
38
+ var GPU_PRESETS = {
39
+ /**
40
+ * 快速滑入(GPU 加速)
41
+ */
42
+ gpuSlideIn: {
43
+ from: {
44
+ transform: "translate3d(0, -100%, 0)",
45
+ opacity: 0
46
+ },
47
+ to: {
48
+ transform: "translate3d(0, 0, 0)",
49
+ opacity: 1
50
+ }
51
+ },
52
+ /**
53
+ * 快速滑出(GPU 加速)
54
+ */
55
+ gpuSlideOut: {
56
+ from: {
57
+ transform: "translate3d(0, 0, 0)",
58
+ opacity: 1
59
+ },
60
+ to: {
61
+ transform: "translate3d(0, -100%, 0)",
62
+ opacity: 0
63
+ }
64
+ },
65
+ /**
66
+ * 缩放进入(GPU 加速)
67
+ */
68
+ gpuZoomIn: {
69
+ from: {
70
+ transform: "translate3d(-50%, -50%, 0) scale(0)",
71
+ opacity: 0
72
+ },
73
+ to: {
74
+ transform: "translate3d(-50%, -50%, 0) scale(1)",
75
+ opacity: 1
76
+ }
77
+ },
78
+ /**
79
+ * 缩放离开(GPU 加速)
80
+ */
81
+ gpuZoomOut: {
82
+ from: {
83
+ transform: "translate3d(-50%, -50%, 0) scale(1)",
84
+ opacity: 1
85
+ },
86
+ to: {
87
+ transform: "translate3d(-50%, -50%, 0) scale(0)",
88
+ opacity: 0
89
+ }
90
+ },
91
+ /**
92
+ * 3D 旋转进入
93
+ */
94
+ rotate3dIn: {
95
+ from: {
96
+ transform: "rotate3d(0, 1, 0, 90deg)",
97
+ opacity: 0
98
+ },
99
+ to: {
100
+ transform: "rotate3d(0, 0, 0, 0deg)",
101
+ opacity: 1
102
+ }
103
+ },
104
+ /**
105
+ * 3D 旋转离开
106
+ */
107
+ rotate3dOut: {
108
+ from: {
109
+ transform: "rotate3d(0, 0, 0, 0deg)",
110
+ opacity: 1
111
+ },
112
+ to: {
113
+ transform: "rotate3d(0, 1, 0, 90deg)",
114
+ opacity: 0
115
+ }
116
+ },
117
+ /**
118
+ * 弹性弹跳(GPU 加速)
119
+ */
120
+ elasticBounce: {
121
+ "0%": {
122
+ transform: "translate3d(0, 0, 0) scale(1)",
123
+ opacity: 1
124
+ },
125
+ "30%": {
126
+ transform: "translate3d(0, -30px, 0) scale(1.1)",
127
+ opacity: 1
128
+ },
129
+ "50%": {
130
+ transform: "translate3d(0, -15px, 0) scale(0.95)",
131
+ opacity: 1
132
+ },
133
+ "70%": {
134
+ transform: "translate3d(0, -7px, 0) scale(1.02)",
135
+ opacity: 1
136
+ },
137
+ "100%": {
138
+ transform: "translate3d(0, 0, 0) scale(1)",
139
+ opacity: 1
140
+ }
141
+ },
142
+ /**
143
+ * 翻转进入
144
+ */
145
+ flipIn: {
146
+ from: {
147
+ transform: "perspective(400px) rotate3d(1, 0, 0, 90deg)",
148
+ opacity: 0
149
+ },
150
+ "40%": {
151
+ transform: "perspective(400px) rotate3d(1, 0, 0, -10deg)",
152
+ opacity: 1
153
+ },
154
+ "100%": {
155
+ transform: "perspective(400px) rotate3d(1, 0, 0, 0deg)",
156
+ opacity: 1
157
+ }
158
+ },
159
+ /**
160
+ * 翻转离开
161
+ */
162
+ flipOut: {
163
+ from: {
164
+ transform: "perspective(400px) rotate3d(1, 0, 0, 0deg)",
165
+ opacity: 1
166
+ },
167
+ "30%": {
168
+ transform: "perspective(400px) rotate3d(1, 0, 0, 20deg)",
169
+ opacity: 1
170
+ },
171
+ "100%": {
172
+ transform: "perspective(400px) rotate3d(1, 0, 0, -90deg)",
173
+ opacity: 0
174
+ }
175
+ }
176
+ };
177
+ var PerformanceOptimizer = class {
178
+ constructor(options = DEFAULT_GPU_OPTIONS) {
179
+ this.activeAnimations = /* @__PURE__ */ new Set();
180
+ this.rafId = null;
181
+ this.batchedUpdates = /* @__PURE__ */ new Map();
182
+ this.options = { ...DEFAULT_GPU_OPTIONS, ...options };
183
+ this.gpuEnabled = this.checkGPUAvailability();
184
+ }
185
+ checkGPUAvailability() {
186
+ if (typeof window === "undefined") return false;
187
+ try {
188
+ const canvas = document.createElement("canvas");
189
+ const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
190
+ return !!gl;
191
+ } catch {
192
+ return false;
193
+ }
194
+ }
195
+ isGPUAvailable() {
196
+ return this.gpuEnabled;
197
+ }
198
+ shouldUseGPU(properties) {
199
+ if (!this.gpuEnabled) return false;
200
+ const gpuFriendly = ["transform", "opacity", "filter"];
201
+ return properties.every(
202
+ (prop) => gpuFriendly.some((gpuProp) => prop.toLowerCase().includes(gpuProp))
203
+ );
204
+ }
205
+ optimizeElement(element) {
206
+ if (this.shouldUseGPU(["transform", "opacity"])) {
207
+ enableGPUAcceleration(element, this.options);
208
+ }
209
+ }
210
+ batchAnimation(id, update) {
211
+ this.batchedUpdates.set(id, update);
212
+ if (this.rafId === null) {
213
+ this.rafId = requestAnimationFrame(() => {
214
+ this.flushBatchedUpdates();
215
+ });
216
+ }
217
+ }
218
+ flushBatchedUpdates() {
219
+ this.batchedUpdates.forEach((update) => update());
220
+ this.batchedUpdates.clear();
221
+ this.rafId = null;
222
+ }
223
+ trackAnimation(id) {
224
+ this.activeAnimations.add(id);
225
+ }
226
+ untrackAnimation(id) {
227
+ this.activeAnimations.delete(id);
228
+ }
229
+ getActiveAnimationCount() {
230
+ return this.activeAnimations.size;
231
+ }
232
+ cleanup() {
233
+ if (this.rafId !== null) {
234
+ cancelAnimationFrame(this.rafId);
235
+ this.rafId = null;
236
+ }
237
+ this.batchedUpdates.clear();
238
+ this.activeAnimations.clear();
239
+ }
240
+ };
241
+ var globalOptimizer = null;
242
+ function getGlobalOptimizer() {
243
+ if (!globalOptimizer) {
244
+ globalOptimizer = new PerformanceOptimizer();
245
+ }
246
+ return globalOptimizer;
247
+ }
248
+ function resetGlobalOptimizer(options) {
249
+ if (globalOptimizer) {
250
+ globalOptimizer.cleanup();
251
+ }
252
+ globalOptimizer = new PerformanceOptimizer(options);
253
+ }
254
+
255
+ // src/index.ts
256
+ var EASING_FUNCTIONS = {
257
+ linear: (t) => t,
258
+ ease: (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
259
+ "ease-in": (t) => t * t * t,
260
+ "ease-out": (t) => --t * t * t + 1,
261
+ "ease-in-out": (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
262
+ "ease-in-quad": (t) => t * t,
263
+ "ease-out-quad": (t) => t * (2 - t),
264
+ "ease-in-out-quad": (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
265
+ "ease-in-cubic": (t) => t * t * t,
266
+ "ease-out-cubic": (t) => --t * t * t + 1,
267
+ "ease-in-out-cubic": (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
268
+ "ease-in-quart": (t) => t * t * t * t,
269
+ "ease-out-quart": (t) => 1 - --t * t * t * t,
270
+ "ease-in-out-quart": (t) => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t,
271
+ "ease-in-quint": (t) => t * t * t * t * t,
272
+ "ease-out-quint": (t) => 1 + --t * t * t * t * t,
273
+ "ease-in-out-quint": (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t,
274
+ "ease-in-sine": (t) => 1 - Math.cos(t * Math.PI / 2),
275
+ "ease-out-sine": (t) => Math.sin(t * Math.PI / 2),
276
+ "ease-in-out-sine": (t) => -(Math.cos(Math.PI * t) - 1) / 2,
277
+ "ease-in-expo": (t) => t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),
278
+ "ease-out-expo": (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
279
+ "ease-in-out-expo": (t) => t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2,
280
+ "ease-in-circ": (t) => 1 - Math.sqrt(1 - t * t),
281
+ "ease-out-circ": (t) => Math.sqrt(1 - --t * t),
282
+ "ease-in-out-circ": (t) => t < 0.5 ? (1 - Math.sqrt(1 - 4 * t * t)) / 2 : (Math.sqrt(1 - (2 * t - 2) * (2 * t - 2)) + 1) / 2,
283
+ "ease-in-back": (t) => {
284
+ const c1 = 1.70158;
285
+ const c3 = c1 + 1;
286
+ return c3 * t * t * t - c1 * t * t;
287
+ },
288
+ "ease-out-back": (t) => {
289
+ const c1 = 1.70158;
290
+ const c3 = c1 + 1;
291
+ return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
292
+ },
293
+ "ease-in-out-back": (t) => {
294
+ const c1 = 1.70158;
295
+ const c2 = c1 * 1.525;
296
+ return t < 0.5 ? Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2) / 2 : (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
297
+ },
298
+ spring: (t) => {
299
+ const c4 = 2 * Math.PI / 3;
300
+ return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
301
+ }
302
+ };
303
+ var idCounter = 0;
304
+ function generateId() {
305
+ return `lyt-animation-${++idCounter}`;
306
+ }
307
+ function getEasingFunction(easing) {
308
+ if (typeof easing === "function") {
309
+ return easing;
310
+ }
311
+ return EASING_FUNCTIONS[easing] || EASING_FUNCTIONS.ease;
312
+ }
313
+ function createAnimation(animateFn, options = {}) {
314
+ const {
315
+ duration = 300,
316
+ easing = "ease",
317
+ delay = 0,
318
+ iterations = 1,
319
+ direction = "normal",
320
+ fill = "none",
321
+ onStart,
322
+ onUpdate,
323
+ onComplete,
324
+ onPause,
325
+ onCancel
326
+ } = options;
327
+ const id = generateId();
328
+ const easingFn = getEasingFunction(easing);
329
+ let state = "idle";
330
+ let progress = 0;
331
+ let startTime = 0;
332
+ let pausedTime = 0;
333
+ let animationFrameId = null;
334
+ let currentIteration = 0;
335
+ let isReversed = direction === "reverse" || direction === "alternate-reverse";
336
+ const progressSignal = signal(0);
337
+ function animate(timestamp) {
338
+ if (state !== "playing") return;
339
+ if (!startTime) {
340
+ startTime = timestamp;
341
+ }
342
+ const elapsed = timestamp - startTime - delay;
343
+ if (elapsed >= 0) {
344
+ const rawProgress = Math.min(elapsed / duration, 1);
345
+ let adjustedProgress = rawProgress;
346
+ if (isReversed) {
347
+ adjustedProgress = 1 - rawProgress;
348
+ }
349
+ if (direction === "alternate" || direction === "alternate-reverse") {
350
+ const cycleProgress = rawProgress * iterations;
351
+ const currentCycle = Math.floor(cycleProgress);
352
+ const cycleProgressRemainder = cycleProgress - currentCycle;
353
+ adjustedProgress = currentCycle % 2 === 0 ? cycleProgressRemainder : 1 - cycleProgressRemainder;
354
+ }
355
+ progress = adjustedProgress;
356
+ progressSignal.set(adjustedProgress);
357
+ const easedProgress = easingFn(adjustedProgress);
358
+ animateFn(easedProgress);
359
+ if (onUpdate) {
360
+ onUpdate(easedProgress);
361
+ }
362
+ if (rawProgress >= 1) {
363
+ currentIteration++;
364
+ if (iterations === -1 || currentIteration < iterations) {
365
+ startTime = timestamp - (elapsed - duration);
366
+ animationFrameId = requestAnimationFrame(animate);
367
+ return;
368
+ } else {
369
+ state = "completed";
370
+ if (onComplete) {
371
+ onComplete();
372
+ }
373
+ }
374
+ } else {
375
+ animationFrameId = requestAnimationFrame(animate);
376
+ }
377
+ } else {
378
+ animationFrameId = requestAnimationFrame(animate);
379
+ }
380
+ }
381
+ function play() {
382
+ if (state === "completed" || state === "cancelled") {
383
+ reset();
384
+ }
385
+ state = "playing";
386
+ if (onStart) {
387
+ onStart();
388
+ }
389
+ animationFrameId = requestAnimationFrame(animate);
390
+ }
391
+ function pause() {
392
+ if (state !== "playing") return;
393
+ state = "paused";
394
+ pausedTime = performance.now();
395
+ if (animationFrameId) {
396
+ cancelAnimationFrame(animationFrameId);
397
+ animationFrameId = null;
398
+ }
399
+ if (onPause) {
400
+ onPause();
401
+ }
402
+ }
403
+ function cancel() {
404
+ if (animationFrameId) {
405
+ cancelAnimationFrame(animationFrameId);
406
+ animationFrameId = null;
407
+ }
408
+ state = "cancelled";
409
+ if (onCancel) {
410
+ onCancel();
411
+ }
412
+ }
413
+ function reset() {
414
+ if (animationFrameId) {
415
+ cancelAnimationFrame(animationFrameId);
416
+ animationFrameId = null;
417
+ }
418
+ state = "idle";
419
+ progress = 0;
420
+ currentIteration = 0;
421
+ progressSignal.set(0);
422
+ startTime = 0;
423
+ pausedTime = 0;
424
+ isReversed = direction === "reverse" || direction === "alternate-reverse";
425
+ }
426
+ function seek(newProgress) {
427
+ progress = Math.max(0, Math.min(1, newProgress));
428
+ progressSignal.set(progress);
429
+ const easedProgress = easingFn(progress);
430
+ animateFn(easedProgress);
431
+ if (onUpdate) {
432
+ onUpdate(easedProgress);
433
+ }
434
+ }
435
+ function reverse() {
436
+ isReversed = !isReversed;
437
+ }
438
+ return {
439
+ id,
440
+ get state() {
441
+ return state;
442
+ },
443
+ get progress() {
444
+ return progressSignal();
445
+ },
446
+ play,
447
+ pause,
448
+ cancel,
449
+ reset,
450
+ seek,
451
+ reverse
452
+ };
453
+ }
454
+ function transitionElement(element, toggle, options = {}) {
455
+ const {
456
+ property = "all",
457
+ duration = 300,
458
+ easing = "ease",
459
+ delay = 0,
460
+ onBeforeEnter,
461
+ onEnter,
462
+ onAfterEnter,
463
+ onBeforeLeave,
464
+ onLeave,
465
+ onAfterLeave
466
+ } = options;
467
+ const propertyStr = Array.isArray(property) ? property.join(", ") : property;
468
+ const easingFn = getEasingFunction(easing);
469
+ if (toggle) {
470
+ if (onBeforeEnter) {
471
+ onBeforeEnter();
472
+ }
473
+ element.style.transition = `${propertyStr} ${duration}ms ${typeof easing === "string" ? easing : "ease"} ${delay}ms`;
474
+ requestAnimationFrame(() => {
475
+ if (onEnter) {
476
+ onEnter();
477
+ }
478
+ setTimeout(() => {
479
+ if (onAfterEnter) {
480
+ onAfterEnter();
481
+ }
482
+ }, duration + delay);
483
+ });
484
+ } else {
485
+ if (onBeforeLeave) {
486
+ onBeforeLeave();
487
+ }
488
+ element.style.transition = `${propertyStr} ${duration}ms ${typeof easing === "string" ? easing : "ease"} ${delay}ms`;
489
+ requestAnimationFrame(() => {
490
+ if (onLeave) {
491
+ onLeave();
492
+ }
493
+ setTimeout(() => {
494
+ if (onAfterLeave) {
495
+ onAfterLeave();
496
+ }
497
+ }, duration + delay);
498
+ });
499
+ }
500
+ }
501
+ function createKeyframeAnimation(element, keyframes, options = {}) {
502
+ const {
503
+ duration = 300,
504
+ easing = "ease",
505
+ delay = 0,
506
+ iterations = 1,
507
+ direction = "normal",
508
+ fill = "forwards",
509
+ onStart,
510
+ onUpdate,
511
+ onComplete,
512
+ onPause,
513
+ onCancel
514
+ } = options;
515
+ if (typeof element.animate === "function") {
516
+ let webAnimation = null;
517
+ let updateInterval = null;
518
+ const id = generateId();
519
+ let isPlaying = false;
520
+ const progressSignal = signal(0);
521
+ const play = () => {
522
+ if (!webAnimation) {
523
+ webAnimation = element.animate(keyframes, {
524
+ duration,
525
+ easing: typeof easing === "string" ? easing : "ease",
526
+ delay,
527
+ iterations: iterations === -1 ? Infinity : iterations,
528
+ direction,
529
+ fill
530
+ });
531
+ webAnimation.onfinish = () => {
532
+ if (onComplete) {
533
+ onComplete();
534
+ }
535
+ };
536
+ webAnimation.oncancel = () => {
537
+ if (onCancel) {
538
+ onCancel();
539
+ }
540
+ };
541
+ if (onUpdate) {
542
+ updateInterval = window.setInterval(() => {
543
+ if (webAnimation && webAnimation.currentTime !== null && webAnimation.currentTime !== void 0) {
544
+ const progress = webAnimation.currentTime / duration;
545
+ progressSignal.set(progress);
546
+ onUpdate(progress);
547
+ }
548
+ }, 16);
549
+ }
550
+ } else {
551
+ webAnimation.play();
552
+ }
553
+ isPlaying = true;
554
+ if (onStart) {
555
+ onStart();
556
+ }
557
+ };
558
+ const pause = () => {
559
+ if (webAnimation) {
560
+ webAnimation.pause();
561
+ isPlaying = false;
562
+ if (onPause) {
563
+ onPause();
564
+ }
565
+ if (updateInterval) {
566
+ clearInterval(updateInterval);
567
+ updateInterval = null;
568
+ }
569
+ }
570
+ };
571
+ const cancel = () => {
572
+ if (webAnimation) {
573
+ webAnimation.cancel();
574
+ webAnimation = null;
575
+ if (updateInterval) {
576
+ clearInterval(updateInterval);
577
+ updateInterval = null;
578
+ }
579
+ }
580
+ };
581
+ const reset = () => {
582
+ if (webAnimation) {
583
+ webAnimation.cancel();
584
+ webAnimation = null;
585
+ progressSignal.set(0);
586
+ if (updateInterval) {
587
+ clearInterval(updateInterval);
588
+ updateInterval = null;
589
+ }
590
+ }
591
+ };
592
+ const seek = (progress) => {
593
+ if (webAnimation) {
594
+ webAnimation.currentTime = progress * duration;
595
+ progressSignal.set(progress);
596
+ }
597
+ };
598
+ const reverse = () => {
599
+ if (webAnimation) {
600
+ webAnimation.reverse();
601
+ }
602
+ };
603
+ return {
604
+ id,
605
+ get state() {
606
+ return isPlaying ? "playing" : webAnimation ? "paused" : "idle";
607
+ },
608
+ get progress() {
609
+ return progressSignal();
610
+ },
611
+ play,
612
+ pause,
613
+ cancel,
614
+ reset,
615
+ seek,
616
+ reverse
617
+ };
618
+ }
619
+ return createAnimation(() => {
620
+ }, options);
621
+ }
622
+ var PRESETS = {
623
+ /** 淡入 */
624
+ fadeIn: {
625
+ from: { opacity: 0 },
626
+ to: { opacity: 1 }
627
+ },
628
+ /** 淡出 */
629
+ fadeOut: {
630
+ from: { opacity: 1 },
631
+ to: { opacity: 0 }
632
+ },
633
+ /** 滑入(上方) */
634
+ slideInUp: {
635
+ from: { transform: "translateY(100%)", opacity: 0 },
636
+ to: { transform: "translateY(0)", opacity: 1 }
637
+ },
638
+ /** 滑入(下方) */
639
+ slideInDown: {
640
+ from: { transform: "translateY(-100%)", opacity: 0 },
641
+ to: { transform: "translateY(0)", opacity: 1 }
642
+ },
643
+ /** 滑入(左侧) */
644
+ slideInLeft: {
645
+ from: { transform: "translateX(-100%)", opacity: 0 },
646
+ to: { transform: "translateX(0)", opacity: 1 }
647
+ },
648
+ /** 滑入(右侧) */
649
+ slideInRight: {
650
+ from: { transform: "translateX(100%)", opacity: 0 },
651
+ to: { transform: "translateX(0)", opacity: 1 }
652
+ },
653
+ /** 缩放进入 */
654
+ zoomIn: {
655
+ from: { transform: "scale(0)", opacity: 0 },
656
+ to: { transform: "scale(1)", opacity: 1 }
657
+ },
658
+ /** 缩放离开 */
659
+ zoomOut: {
660
+ from: { transform: "scale(1)", opacity: 1 },
661
+ to: { transform: "scale(0)", opacity: 0 }
662
+ },
663
+ /** 弹跳进入 */
664
+ bounceIn: {
665
+ from: { transform: "scale(0.3)", opacity: 0 },
666
+ "40%": { transform: "scale(1.1)" },
667
+ "70%": { transform: "scale(0.9)" },
668
+ to: { transform: "scale(1)", opacity: 1 }
669
+ },
670
+ /** 摇摆进入 */
671
+ shake: {
672
+ "10%, 90%": { transform: "translate3d(-1px, 0, 0)" },
673
+ "20%, 80%": { transform: "translate3d(2px, 0, 0)" },
674
+ "30%, 50%, 70%": { transform: "translate3d(-4px, 0, 0)" },
675
+ "40%, 60%": { transform: "translate3d(4px, 0, 0)" }
676
+ }
677
+ };
678
+ function createAnimationManager(options = {}) {
679
+ const {
680
+ defaultDuration = 300,
681
+ defaultEasing = "ease",
682
+ autoCleanup = true
683
+ } = options;
684
+ const animations = /* @__PURE__ */ new Map();
685
+ function animate(animateFn, opts) {
686
+ const animation = createAnimation(animateFn, {
687
+ duration: defaultDuration,
688
+ easing: defaultEasing,
689
+ ...opts
690
+ });
691
+ animations.set(animation.id, animation);
692
+ return animation;
693
+ }
694
+ function applyPreset(element, presetName, opts) {
695
+ const preset = PRESETS[presetName];
696
+ if (!preset) {
697
+ throw new Error(`Preset "${presetName}" not found`);
698
+ }
699
+ const keyframes = [];
700
+ for (const key in preset) {
701
+ const keyframe = preset[key];
702
+ let offset;
703
+ if (key === "from") offset = 0;
704
+ else if (key === "to") offset = 1;
705
+ else {
706
+ const match = key.match(/^(\d+)%$/);
707
+ if (match) offset = parseInt(match[1], 10) / 100;
708
+ else continue;
709
+ }
710
+ keyframes.push({
711
+ offset,
712
+ ...keyframe
713
+ });
714
+ }
715
+ const animation = createKeyframeAnimation(element, keyframes, {
716
+ duration: defaultDuration,
717
+ easing: defaultEasing,
718
+ ...opts
719
+ });
720
+ animations.set(animation.id, animation);
721
+ return animation;
722
+ }
723
+ function remove(id) {
724
+ const animation = animations.get(id);
725
+ if (animation) {
726
+ animation.cancel();
727
+ animations.delete(id);
728
+ }
729
+ }
730
+ function clear() {
731
+ for (const [id, animation] of animations) {
732
+ animation.cancel();
733
+ }
734
+ animations.clear();
735
+ }
736
+ return {
737
+ animate,
738
+ applyPreset,
739
+ transitionElement,
740
+ remove,
741
+ clear
742
+ };
743
+ }
744
+ var pluginAnimation = definePlugin({
745
+ name: "animation",
746
+ version: "6.0.0",
747
+ description: "LytJS official animation plugin with CSS transitions and animations",
748
+ author: "LytJS Team",
749
+ keywords: ["lytjs", "animation", "transition", "css-animation"],
750
+ schema: {
751
+ type: "object",
752
+ object: {
753
+ properties: {
754
+ defaultDuration: { type: "number", default: 300 },
755
+ defaultEasing: { type: "string", default: "ease" },
756
+ autoCleanup: { type: "boolean", default: true }
757
+ }
758
+ }
759
+ },
760
+ install(app, options) {
761
+ const animationManager = createAnimationManager(options);
762
+ app.config.globalProperties.$animation = animationManager;
763
+ app.provide("lyt-animation", animationManager);
764
+ }
765
+ });
766
+ var index_default = pluginAnimation;
767
+ export {
768
+ GPU_PRESETS,
769
+ PRESETS,
770
+ PerformanceOptimizer,
771
+ canUseGPU,
772
+ createAnimation,
773
+ createKeyframeAnimation,
774
+ index_default as default,
775
+ disableGPUAcceleration,
776
+ enableGPUAcceleration,
777
+ getGlobalOptimizer,
778
+ resetGlobalOptimizer,
779
+ to3DTransform,
780
+ transitionElement
781
+ };