@luanlu/mk-motion 1.2.0 → 1.2.1

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.
Files changed (98) hide show
  1. package/package.json +2 -4
  2. package/src/a11y/focus-trap.ts +64 -0
  3. package/src/a11y/keyboard.ts +43 -0
  4. package/src/components/alert/alert.css +111 -0
  5. package/src/components/alert/alert.ts +107 -0
  6. package/src/components/avatar/avatar.css +112 -0
  7. package/src/components/avatar/avatar.ts +175 -0
  8. package/src/components/breadcrumb/breadcrumb.css +31 -0
  9. package/src/components/breadcrumb/breadcrumb.ts +71 -0
  10. package/src/components/button/button.css +108 -0
  11. package/src/components/button/button.ts +140 -0
  12. package/src/components/card/card.css +52 -0
  13. package/src/components/card/card.ts +87 -0
  14. package/src/components/collapse/collapse.css +76 -0
  15. package/src/components/collapse/collapse.ts +168 -0
  16. package/src/components/dialog/dialog.css +78 -0
  17. package/src/components/dialog/dialog.ts +164 -0
  18. package/src/components/drawer/drawer.css +73 -0
  19. package/src/components/drawer/drawer.ts +131 -0
  20. package/src/components/empty/empty.css +36 -0
  21. package/src/components/empty/empty.ts +85 -0
  22. package/src/components/form/checkbox.css +56 -0
  23. package/src/components/form/checkbox.ts +119 -0
  24. package/src/components/form/radio.css +57 -0
  25. package/src/components/form/radio.ts +153 -0
  26. package/src/components/form/select.css +91 -0
  27. package/src/components/form/select.ts +174 -0
  28. package/src/components/form/slider.css +56 -0
  29. package/src/components/form/slider.ts +148 -0
  30. package/src/components/input/input.css +92 -0
  31. package/src/components/input/input.ts +162 -0
  32. package/src/components/layout/divider.css +32 -0
  33. package/src/components/layout/divider.ts +42 -0
  34. package/src/components/layout/row.css +64 -0
  35. package/src/components/layout/row.ts +57 -0
  36. package/src/components/layout/space.css +14 -0
  37. package/src/components/layout/space.ts +48 -0
  38. package/src/components/loading/loading.css +37 -0
  39. package/src/components/loading/loading.ts +46 -0
  40. package/src/components/menu/menu.css +121 -0
  41. package/src/components/menu/menu.ts +187 -0
  42. package/src/components/message/message.css +64 -0
  43. package/src/components/message/message.ts +96 -0
  44. package/src/components/popover/popover.css +73 -0
  45. package/src/components/popover/popover.ts +279 -0
  46. package/src/components/progress/progress.css +112 -0
  47. package/src/components/progress/progress.ts +171 -0
  48. package/src/components/steps/steps.css +127 -0
  49. package/src/components/steps/steps.ts +102 -0
  50. package/src/components/styles/components.css +28 -0
  51. package/src/components/styles/reset.css +24 -0
  52. package/src/components/styles/tokens.css +248 -0
  53. package/src/components/styles/variables.css +24 -0
  54. package/src/components/switch/switch.css +53 -0
  55. package/src/components/switch/switch.ts +103 -0
  56. package/src/components/table/table.css +192 -0
  57. package/src/components/table/table.ts +370 -0
  58. package/src/components/tabs/tabs.css +138 -0
  59. package/src/components/tabs/tabs.ts +211 -0
  60. package/src/components/tag/tag.css +123 -0
  61. package/src/components/tag/tag.ts +112 -0
  62. package/src/components/tooltip/tooltip.css +66 -0
  63. package/src/components/tooltip/tooltip.ts +185 -0
  64. package/src/core/animator.ts +124 -0
  65. package/src/core/timeline.ts +128 -0
  66. package/src/core/utils.ts +47 -0
  67. package/src/effects/glitch.ts +99 -0
  68. package/src/effects/particle.ts +134 -0
  69. package/src/effects/text-split.ts +95 -0
  70. package/src/effects/wave-text.ts +88 -0
  71. package/src/gesture/draggable.ts +130 -0
  72. package/src/gesture/spring.ts +152 -0
  73. package/src/index.ts +162 -0
  74. package/src/interactive/coverflow.ts +100 -0
  75. package/src/interactive/cursor-trail.ts +113 -0
  76. package/src/interactive/flip-card.ts +114 -0
  77. package/src/interactive/magnetic.ts +121 -0
  78. package/src/micro/hover-lift.ts +94 -0
  79. package/src/micro/ripple.ts +130 -0
  80. package/src/motion/component-motion.ts +177 -0
  81. package/src/presets/index.ts +69 -0
  82. package/src/scroll/scroll-trigger.ts +104 -0
  83. package/src/styles/animations.css +135 -0
  84. package/src/styles/element-plus.css +174 -0
  85. package/src/text/count-up.ts +108 -0
  86. package/src/text/typewriter.ts +109 -0
  87. package/src/theme/dark.css +19 -0
  88. package/src/theme/light.css +19 -0
  89. package/src/theme/theme.ts +65 -0
  90. package/src/transitions/blur-reveal.ts +92 -0
  91. package/src/transitions/collapse.ts +112 -0
  92. package/src/transitions/lazy-image.ts +87 -0
  93. package/src/transitions/list.ts +75 -0
  94. package/src/transitions/loading.ts +95 -0
  95. package/src/transitions/parallax.ts +60 -0
  96. package/src/transitions/shimmer.ts +105 -0
  97. package/src/transitions/toast.ts +151 -0
  98. package/src/types.d.ts +4 -0
@@ -0,0 +1,177 @@
1
+ import { Animator } from '../core/animator.ts'
2
+ import type { AnimationName } from '../core/utils.ts'
3
+
4
+ export type MicroAnimation = 'lift' | 'glow' | 'scale' | 'slideUp' | 'none'
5
+
6
+ export interface MotionOptions {
7
+ /** Mount entrance animation */
8
+ enter?: 'fadeIn' | 'slideInUp' | 'slideInDown' | 'slideInLeft' | 'slideInRight' | 'zoomIn' | 'bounceIn' | 'none'
9
+ /** Unmount exit animation */
10
+ exit?: 'fadeOut' | 'slideOutUp' | 'slideOutDown' | 'zoomOut' | 'none'
11
+ /** Hover micro-interaction */
12
+ hover?: MicroAnimation
13
+ /** Active/press micro-interaction */
14
+ active?: 'press' | 'none'
15
+ /** Focus ring animation */
16
+ focus?: 'ring' | 'none'
17
+ /** Duration in ms */
18
+ duration?: number
19
+ /** Delay in ms */
20
+ delay?: number
21
+ /** Easing */
22
+ easing?: string
23
+ }
24
+
25
+ const defaultOptions: Required<MotionOptions> = {
26
+ enter: 'fadeIn',
27
+ exit: 'fadeOut',
28
+ hover: 'none',
29
+ active: 'none',
30
+ focus: 'none',
31
+ duration: 250,
32
+ delay: 0,
33
+ easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
34
+ }
35
+
36
+ /**
37
+ * Attach motion behaviors to a DOM element.
38
+ * Returns controller to play enter/exit and manage state animations.
39
+ */
40
+ export function withMotion(el: HTMLElement, options: MotionOptions = {}) {
41
+ const opts = { ...defaultOptions, ...options }
42
+ const animator = opts.enter !== 'none' ? new Animator(el) : null
43
+ const style = el.style
44
+ const originalTransition = style.transition
45
+
46
+ // Hover
47
+ let hoverActive = false
48
+ function onMouseEnter() {
49
+ if (opts.hover === 'none') return
50
+ hoverActive = true
51
+ applyHover(true)
52
+ }
53
+ function onMouseLeave() {
54
+ if (!hoverActive) return
55
+ hoverActive = false
56
+ applyHover(false)
57
+ }
58
+
59
+ function applyHover(active: boolean) {
60
+ const t = `transform ${opts.duration}ms ${opts.easing}, box-shadow ${opts.duration}ms ${opts.easing}`
61
+ switch (opts.hover) {
62
+ case 'lift':
63
+ style.transition = t
64
+ style.transform = active ? 'translateY(-2px)' : ''
65
+ style.boxShadow = active ? 'var(--mk-shadow-md)' : ''
66
+ break
67
+ case 'glow':
68
+ style.transition = `box-shadow ${opts.duration}ms ${opts.easing}`
69
+ style.boxShadow = active ? 'var(--mk-shadow-glow)' : ''
70
+ break
71
+ case 'scale':
72
+ style.transition = `transform ${opts.duration}ms ${opts.easing}`
73
+ style.transform = active ? 'scale(1.02)' : ''
74
+ break
75
+ case 'slideUp':
76
+ style.transition = t
77
+ style.transform = active ? 'translateY(-4px)' : ''
78
+ break
79
+ }
80
+ }
81
+
82
+ // Active / Press
83
+ function onMouseDown() {
84
+ if (opts.active === 'press') {
85
+ style.transition = `transform ${opts.duration * 0.5}ms ${opts.easing}`
86
+ style.transform = 'scale(0.97)'
87
+ }
88
+ }
89
+ function onMouseUp() {
90
+ if (opts.active === 'press') {
91
+ style.transform = hoverActive ? (opts.hover === 'lift' ? 'translateY(-2px)' : opts.hover === 'scale' ? 'scale(1.02)' : '') : ''
92
+ }
93
+ }
94
+
95
+ // Focus ring
96
+ function onFocus() {
97
+ if (opts.focus === 'ring') {
98
+ style.outline = 'none'
99
+ style.boxShadow = '0 0 0 2px var(--mk-primary-muted), 0 0 0 4px var(--mk-primary)'
100
+ style.transition = `box-shadow ${opts.duration}ms ${opts.easing}`
101
+ }
102
+ }
103
+ function onBlur() {
104
+ if (opts.focus === 'ring') {
105
+ style.boxShadow = ''
106
+ }
107
+ }
108
+
109
+ // Attach listeners
110
+ el.addEventListener('mouseenter', onMouseEnter)
111
+ el.addEventListener('mouseleave', onMouseLeave)
112
+ el.addEventListener('mousedown', onMouseDown)
113
+ el.addEventListener('mouseup', onMouseUp)
114
+ el.addEventListener('focus', onFocus)
115
+ el.addEventListener('blur', onBlur)
116
+
117
+ return {
118
+ /** Play entrance animation */
119
+ async playEnter() {
120
+ if (!animator || opts.enter === 'none') return
121
+ await animator.animate(opts.enter, { duration: opts.duration, delay: opts.delay })
122
+ },
123
+
124
+ /** Play exit animation. Returns a Promise that resolves when animation completes. */
125
+ async playExit() {
126
+ if (!animator || opts.exit === 'none') return
127
+ await animator.animate(opts.exit, { duration: opts.duration })
128
+ },
129
+
130
+ /** Programmatically set hover state */
131
+ setHover(active: boolean) {
132
+ if (active) onMouseEnter()
133
+ else onMouseLeave()
134
+ },
135
+
136
+ /** Clean up all listeners and styles */
137
+ destroy() {
138
+ el.removeEventListener('mouseenter', onMouseEnter)
139
+ el.removeEventListener('mouseleave', onMouseLeave)
140
+ el.removeEventListener('mousedown', onMouseDown)
141
+ el.removeEventListener('mouseup', onMouseUp)
142
+ el.removeEventListener('focus', onFocus)
143
+ el.removeEventListener('blur', onBlur)
144
+ style.transition = originalTransition
145
+ style.transform = ''
146
+ style.boxShadow = ''
147
+ style.outline = ''
148
+ animator?.stop()
149
+ },
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Stagger children entrance animation.
155
+ */
156
+ export function staggerEnter(
157
+ container: HTMLElement,
158
+ selector: string,
159
+ _animation?: AnimationName,
160
+ options?: { duration?: number; stagger?: number; delay?: number }
161
+ ) {
162
+ const children = container.querySelectorAll(selector)
163
+ if (children.length === 0) return
164
+
165
+ const delay = options?.delay ?? 100
166
+ const stagger = options?.stagger ?? 80
167
+ const duration = options?.duration ?? 400
168
+
169
+ children.forEach((el, i) => {
170
+ const htmlEl = el as HTMLElement
171
+ htmlEl.style.opacity = '0'
172
+ setTimeout(() => {
173
+ htmlEl.style.transition = `opacity ${duration}ms ease`
174
+ htmlEl.style.opacity = '1'
175
+ }, delay + i * stagger)
176
+ })
177
+ }
@@ -0,0 +1,69 @@
1
+ import type { AnimationOptions } from '../core/utils.ts'
2
+ import { Animator } from '../core/animator.ts'
3
+
4
+ function $(el: HTMLElement | string) {
5
+ return new Animator(el)
6
+ }
7
+
8
+ /* ---------- Fade ---------- */
9
+ export function fadeIn(el: HTMLElement | string, opts?: AnimationOptions) {
10
+ return $(el).animate('fadeIn', opts)
11
+ }
12
+ export function fadeOut(el: HTMLElement | string, opts?: AnimationOptions) {
13
+ return $(el).animate('fadeOut', opts)
14
+ }
15
+
16
+ /* ---------- Slide ---------- */
17
+ export function slideInUp(el: HTMLElement | string, opts?: AnimationOptions) {
18
+ return $(el).animate('slideInUp', opts)
19
+ }
20
+ export function slideInDown(el: HTMLElement | string, opts?: AnimationOptions) {
21
+ return $(el).animate('slideInDown', opts)
22
+ }
23
+ export function slideInLeft(el: HTMLElement | string, opts?: AnimationOptions) {
24
+ return $(el).animate('slideInLeft', opts)
25
+ }
26
+ export function slideInRight(el: HTMLElement | string, opts?: AnimationOptions) {
27
+ return $(el).animate('slideInRight', opts)
28
+ }
29
+ export function slideOutUp(el: HTMLElement | string, opts?: AnimationOptions) {
30
+ return $(el).animate('slideOutUp', opts)
31
+ }
32
+ export function slideOutDown(el: HTMLElement | string, opts?: AnimationOptions) {
33
+ return $(el).animate('slideOutDown', opts)
34
+ }
35
+
36
+ /* ---------- Zoom ---------- */
37
+ export function zoomIn(el: HTMLElement | string, opts?: AnimationOptions) {
38
+ return $(el).animate('zoomIn', opts)
39
+ }
40
+ export function zoomOut(el: HTMLElement | string, opts?: AnimationOptions) {
41
+ return $(el).animate('zoomOut', opts)
42
+ }
43
+
44
+ /* ---------- Bounce ---------- */
45
+ export function bounceIn(el: HTMLElement | string, opts?: AnimationOptions) {
46
+ return $(el).animate('bounceIn', opts)
47
+ }
48
+ export function bounceOut(el: HTMLElement | string, opts?: AnimationOptions) {
49
+ return $(el).animate('bounceOut', opts)
50
+ }
51
+
52
+ /* ---------- Flip ---------- */
53
+ export function flipInX(el: HTMLElement | string, opts?: AnimationOptions) {
54
+ return $(el).animate('flipInX', opts)
55
+ }
56
+ export function flipInY(el: HTMLElement | string, opts?: AnimationOptions) {
57
+ return $(el).animate('flipInY', opts)
58
+ }
59
+
60
+ /* ---------- Misc ---------- */
61
+ export function shake(el: HTMLElement | string, opts?: AnimationOptions) {
62
+ return $(el).animate('shake', opts)
63
+ }
64
+ export function pulse(el: HTMLElement | string, opts?: AnimationOptions) {
65
+ return $(el).animate('pulse', opts)
66
+ }
67
+ export function rotateIn(el: HTMLElement | string, opts?: AnimationOptions) {
68
+ return $(el).animate('rotateIn', opts)
69
+ }
@@ -0,0 +1,104 @@
1
+ import type { AnimationName } from '../core/utils.ts'
2
+
3
+ export interface ScrollTriggerOptions {
4
+ threshold?: number // 0~1,元素进入视口多少比例时触发
5
+ rootMargin?: string // 类似 CSS margin,扩大/缩小视口判定范围
6
+ once?: boolean // 是否只触发一次
7
+ duration?: number
8
+ easing?: string
9
+ }
10
+
11
+ const DEFAULT_SCROLL_OPTS: Required<ScrollTriggerOptions> = {
12
+ threshold: 0.2,
13
+ rootMargin: '0px',
14
+ once: true,
15
+ duration: 500,
16
+ easing: 'ease',
17
+ }
18
+
19
+ export class ScrollTrigger {
20
+ private observer: IntersectionObserver | null = null
21
+ private elements = new Map<Element, { name: AnimationName; opts: ScrollTriggerOptions }>()
22
+
23
+ watch(
24
+ selector: string | Element | Element[],
25
+ animationName: AnimationName,
26
+ options: ScrollTriggerOptions = {}
27
+ ): this {
28
+ const opts = { ...DEFAULT_SCROLL_OPTS, ...options }
29
+ let targets: Element[]
30
+ if (typeof selector === 'string') {
31
+ targets = Array.from(document.querySelectorAll(selector))
32
+ } else if (Array.isArray(selector)) {
33
+ targets = selector
34
+ } else {
35
+ targets = [selector as Element]
36
+ }
37
+
38
+ if (!this.observer) {
39
+ this.observer = new IntersectionObserver(
40
+ (entries) => this.handleEntries(entries),
41
+ {
42
+ threshold: opts.threshold,
43
+ rootMargin: opts.rootMargin,
44
+ }
45
+ )
46
+ }
47
+
48
+ targets.forEach((el) => {
49
+ this.elements.set(el, { name: animationName, opts })
50
+ this.observer!.observe(el)
51
+ })
52
+
53
+ return this
54
+ }
55
+
56
+ private handleEntries(entries: IntersectionObserverEntry[]): void {
57
+ entries.forEach((entry) => {
58
+ if (entry.isIntersecting) {
59
+ const config = this.elements.get(entry.target)
60
+ if (!config) return
61
+
62
+ const htmlEl = entry.target as HTMLElement
63
+ const className = `mk-animated mk-${config.name}`
64
+
65
+ htmlEl.classList.add(...className.split(' '))
66
+ htmlEl.style.setProperty('--mk-duration', `${config.opts.duration}ms`)
67
+ htmlEl.style.setProperty('--mk-easing', config.opts.easing!)
68
+
69
+ const onEnd = (e: AnimationEvent) => {
70
+ if (e.animationName.startsWith('mk-')) {
71
+ htmlEl.removeEventListener('animationend', onEnd)
72
+ if (config.opts.once) {
73
+ htmlEl.classList.remove(...className.split(' '))
74
+ }
75
+ }
76
+ }
77
+
78
+ htmlEl.addEventListener('animationend', onEnd)
79
+
80
+ if (config.opts.once) {
81
+ this.observer?.unobserve(entry.target)
82
+ this.elements.delete(entry.target)
83
+ }
84
+ }
85
+ })
86
+ }
87
+
88
+ destroy(): void {
89
+ this.observer?.disconnect()
90
+ this.observer = null
91
+ this.elements.clear()
92
+ }
93
+ }
94
+
95
+ /**
96
+ * 快捷方法:为选择器下的所有元素添加滚动触发动画
97
+ */
98
+ export function scrollAnimate(
99
+ selector: string | Element | Element[],
100
+ animationName: AnimationName,
101
+ options?: ScrollTriggerOptions
102
+ ): ScrollTrigger {
103
+ return new ScrollTrigger().watch(selector, animationName, options)
104
+ }
@@ -0,0 +1,135 @@
1
+ /* ========== Fade ========== */
2
+ @keyframes mk-fadeIn {
3
+ from { opacity: 0; }
4
+ to { opacity: 1; }
5
+ }
6
+
7
+ @keyframes mk-fadeOut {
8
+ from { opacity: 1; }
9
+ to { opacity: 0; }
10
+ }
11
+
12
+ /* ========== Slide ========== */
13
+ @keyframes mk-slideInUp {
14
+ from { opacity: 0; transform: translate3d(0, 30px, 0); }
15
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
16
+ }
17
+
18
+ @keyframes mk-slideInDown {
19
+ from { opacity: 0; transform: translate3d(0, -30px, 0); }
20
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
21
+ }
22
+
23
+ @keyframes mk-slideInLeft {
24
+ from { opacity: 0; transform: translate3d(-30px, 0, 0); }
25
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
26
+ }
27
+
28
+ @keyframes mk-slideInRight {
29
+ from { opacity: 0; transform: translate3d(30px, 0, 0); }
30
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
31
+ }
32
+
33
+ @keyframes mk-slideOutUp {
34
+ from { opacity: 1; transform: translate3d(0, 0, 0); }
35
+ to { opacity: 0; transform: translate3d(0, -30px, 0); }
36
+ }
37
+
38
+ @keyframes mk-slideOutDown {
39
+ from { opacity: 1; transform: translate3d(0, 0, 0); }
40
+ to { opacity: 0; transform: translate3d(0, 30px, 0); }
41
+ }
42
+
43
+ /* ========== Zoom ========== */
44
+ @keyframes mk-zoomIn {
45
+ from { opacity: 0; transform: scale3d(0.85, 0.85, 0.85); }
46
+ to { opacity: 1; transform: scale3d(1, 1, 1); }
47
+ }
48
+
49
+ @keyframes mk-zoomOut {
50
+ from { opacity: 1; transform: scale3d(1, 1, 1); }
51
+ to { opacity: 0; transform: scale3d(0.85, 0.85, 0.85); }
52
+ }
53
+
54
+ /* ========== Bounce ========== */
55
+ @keyframes mk-bounceIn {
56
+ 0% { opacity: 0; transform: scale3d(0.3, 0.3, 0.3); }
57
+ 20% { transform: scale3d(1.1, 1.1, 1.1); }
58
+ 40% { transform: scale3d(0.9, 0.9, 0.9); }
59
+ 60% { opacity: 1; transform: scale3d(1.03, 1.03, 1.03); }
60
+ 80% { transform: scale3d(0.97, 0.97, 0.97); }
61
+ 100% { opacity: 1; transform: scale3d(1, 1, 1); }
62
+ }
63
+
64
+ @keyframes mk-bounceOut {
65
+ 20% { transform: scale3d(0.9, 0.9, 0.9); }
66
+ 50%, 55% { opacity: 1; transform: scale3d(1.1, 1.1, 1.1); }
67
+ 100% { opacity: 0; transform: scale3d(0.3, 0.3, 0.3); }
68
+ }
69
+
70
+ /* ========== Flip ========== */
71
+ @keyframes mk-flipInX {
72
+ from { opacity: 0; transform: perspective(400px) rotate3d(1, 0, 0, 90deg); }
73
+ 40% { transform: perspective(400px) rotate3d(1, 0, 0, -20deg); }
74
+ 60% { opacity: 1; transform: perspective(400px) rotate3d(1, 0, 0, 10deg); }
75
+ 80% { transform: perspective(400px) rotate3d(1, 0, 0, -5deg); }
76
+ to { transform: perspective(400px); }
77
+ }
78
+
79
+ @keyframes mk-flipInY {
80
+ from { opacity: 0; transform: perspective(400px) rotate3d(0, 1, 0, 90deg); }
81
+ 40% { transform: perspective(400px) rotate3d(0, 1, 0, -20deg); }
82
+ 60% { opacity: 1; transform: perspective(400px) rotate3d(0, 1, 0, 10deg); }
83
+ 80% { transform: perspective(400px) rotate3d(0, 1, 0, -5deg); }
84
+ to { transform: perspective(400px); }
85
+ }
86
+
87
+ /* ========== Shake ========== */
88
+ @keyframes mk-shake {
89
+ 0%, 100% { transform: translate3d(0, 0, 0); }
90
+ 10%, 30%, 50%, 70%, 90% { transform: translate3d(-8px, 0, 0); }
91
+ 20%, 40%, 60%, 80% { transform: translate3d(8px, 0, 0); }
92
+ }
93
+
94
+ /* ========== Pulse ========== */
95
+ @keyframes mk-pulse {
96
+ 0% { transform: scale3d(1, 1, 1); }
97
+ 50% { transform: scale3d(1.05, 1.05, 1.05); }
98
+ 100% { transform: scale3d(1, 1, 1); }
99
+ }
100
+
101
+ /* ========== Rotate ========== */
102
+ @keyframes mk-rotateIn {
103
+ from { opacity: 0; transform: rotate3d(0, 0, 1, -200deg); }
104
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
105
+ }
106
+
107
+ /* ========== Base animation class ========== */
108
+ .mk-animated {
109
+ animation-duration: var(--mk-duration, 0.5s);
110
+ animation-timing-function: var(--mk-easing, ease);
111
+ animation-fill-mode: both;
112
+ }
113
+
114
+ .mk-animated.mk-infinite {
115
+ animation-iteration-count: infinite;
116
+ }
117
+
118
+ /* ========== Animation presets ========== */
119
+ .mk-fadeIn { animation-name: mk-fadeIn; }
120
+ .mk-fadeOut { animation-name: mk-fadeOut; }
121
+ .mk-slideInUp { animation-name: mk-slideInUp; }
122
+ .mk-slideInDown { animation-name: mk-slideInDown; }
123
+ .mk-slideInLeft { animation-name: mk-slideInLeft; }
124
+ .mk-slideInRight { animation-name: mk-slideInRight; }
125
+ .mk-slideOutUp { animation-name: mk-slideOutUp; }
126
+ .mk-slideOutDown { animation-name: mk-slideOutDown; }
127
+ .mk-zoomIn { animation-name: mk-zoomIn; }
128
+ .mk-zoomOut { animation-name: mk-zoomOut; }
129
+ .mk-bounceIn { animation-name: mk-bounceIn; }
130
+ .mk-bounceOut { animation-name: mk-bounceOut; }
131
+ .mk-flipInX { animation-name: mk-flipInX; }
132
+ .mk-flipInY { animation-name: mk-flipInY; }
133
+ .mk-shake { animation-name: mk-shake; }
134
+ .mk-pulse { animation-name: mk-pulse; }
135
+ .mk-rotateIn { animation-name: mk-rotateIn; }
@@ -0,0 +1,174 @@
1
+ /* ========== Element Plus 风格动画 ========== */
2
+
3
+ /* ----- Fade ----- */
4
+ @keyframes mk-fadeIn {
5
+ from { opacity: 0; }
6
+ to { opacity: 1; }
7
+ }
8
+ @keyframes mk-fadeOut {
9
+ from { opacity: 1; }
10
+ to { opacity: 0; }
11
+ }
12
+
13
+ @keyframes mk-fadeInLinear {
14
+ from { opacity: 0; }
15
+ to { opacity: 1; }
16
+ }
17
+ @keyframes mk-fadeOutLinear {
18
+ from { opacity: 1; }
19
+ to { opacity: 0; }
20
+ }
21
+
22
+ @keyframes mk-fadeInUp {
23
+ from { opacity: 0; transform: translate3d(0, 20px, 0); }
24
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
25
+ }
26
+ @keyframes mk-fadeOutUp {
27
+ from { opacity: 1; transform: translate3d(0, 0, 0); }
28
+ to { opacity: 0; transform: translate3d(0, -20px, 0); }
29
+ }
30
+
31
+ @keyframes mk-fadeInDown {
32
+ from { opacity: 0; transform: translate3d(0, -20px, 0); }
33
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
34
+ }
35
+ @keyframes mk-fadeOutDown {
36
+ from { opacity: 1; transform: translate3d(0, 0, 0); }
37
+ to { opacity: 0; transform: translate3d(0, 20px, 0); }
38
+ }
39
+
40
+ @keyframes mk-fadeInLeft {
41
+ from { opacity: 0; transform: translate3d(20px, 0, 0); }
42
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
43
+ }
44
+ @keyframes mk-fadeOutLeft {
45
+ from { opacity: 1; transform: translate3d(0, 0, 0); }
46
+ to { opacity: 0; transform: translate3d(-20px, 0, 0); }
47
+ }
48
+
49
+ @keyframes mk-fadeInRight {
50
+ from { opacity: 0; transform: translate3d(-20px, 0, 0); }
51
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
52
+ }
53
+ @keyframes mk-fadeOutRight {
54
+ from { opacity: 1; transform: translate3d(0, 0, 0); }
55
+ to { opacity: 0; transform: translate3d(20px, 0, 0); }
56
+ }
57
+
58
+ /* ----- Zoom ----- */
59
+ @keyframes mk-zoomInCenter {
60
+ from { opacity: 0; transform: scale3d(0.7, 0.7, 0.7); }
61
+ to { opacity: 1; transform: scale3d(1, 1, 1); }
62
+ }
63
+ @keyframes mk-zoomOutCenter {
64
+ from { opacity: 1; transform: scale3d(1, 1, 1); }
65
+ to { opacity: 0; transform: scale3d(0.7, 0.7, 0.7); }
66
+ }
67
+
68
+ @keyframes mk-zoomInTop {
69
+ from { opacity: 0; transform: scale3d(0.7, 0.7, 0.7); transform-origin: center top; }
70
+ to { opacity: 1; transform: scale3d(1, 1, 1); transform-origin: center top; }
71
+ }
72
+ @keyframes mk-zoomOutTop {
73
+ from { opacity: 1; transform: scale3d(1, 1, 1); transform-origin: center top; }
74
+ to { opacity: 0; transform: scale3d(0.7, 0.7, 0.7); transform-origin: center top; }
75
+ }
76
+
77
+ @keyframes mk-zoomInBottom {
78
+ from { opacity: 0; transform: scale3d(0.7, 0.7, 0.7); transform-origin: center bottom; }
79
+ to { opacity: 1; transform: scale3d(1, 1, 1); transform-origin: center bottom; }
80
+ }
81
+ @keyframes mk-zoomOutBottom {
82
+ from { opacity: 1; transform: scale3d(1, 1, 1); transform-origin: center bottom; }
83
+ to { opacity: 0; transform: scale3d(0.7, 0.7, 0.7); transform-origin: center bottom; }
84
+ }
85
+
86
+ /* ----- Slide (for Drawer / Modal) ----- */
87
+ @keyframes mk-slideInRight {
88
+ from { transform: translate3d(100%, 0, 0); }
89
+ to { transform: translate3d(0, 0, 0); }
90
+ }
91
+ @keyframes mk-slideOutRight {
92
+ from { transform: translate3d(0, 0, 0); }
93
+ to { transform: translate3d(100%, 0, 0); }
94
+ }
95
+
96
+ @keyframes mk-slideInLeft {
97
+ from { transform: translate3d(-100%, 0, 0); }
98
+ to { transform: translate3d(0, 0, 0); }
99
+ }
100
+ @keyframes mk-slideOutLeft {
101
+ from { transform: translate3d(0, 0, 0); }
102
+ to { transform: translate3d(-100%, 0, 0); }
103
+ }
104
+
105
+ @keyframes mk-slideInTop {
106
+ from { transform: translate3d(0, -100%, 0); }
107
+ to { transform: translate3d(0, 0, 0); }
108
+ }
109
+ @keyframes mk-slideOutTop {
110
+ from { transform: translate3d(0, 0, 0); }
111
+ to { transform: translate3d(0, -100%, 0); }
112
+ }
113
+
114
+ @keyframes mk-slideInBottom {
115
+ from { transform: translate3d(0, 100%, 0); }
116
+ to { transform: translate3d(0, 0, 0); }
117
+ }
118
+ @keyframes mk-slideOutBottom {
119
+ from { transform: translate3d(0, 0, 0); }
120
+ to { transform: translate3d(0, 100%, 0); }
121
+ }
122
+
123
+ /* ----- List stagger ----- */
124
+ @keyframes mk-listItemIn {
125
+ from { opacity: 0; transform: translate3d(0, 16px, 0); }
126
+ to { opacity: 1; transform: translate3d(0, 0, 0); }
127
+ }
128
+
129
+ /* ----- Spinner ----- */
130
+ @keyframes mk-spin {
131
+ from { transform: rotate(0deg); }
132
+ to { transform: rotate(360deg); }
133
+ }
134
+
135
+ /* ----- Base class ----- */
136
+ .mk-transition {
137
+ animation-duration: var(--mk-duration, 0.3s);
138
+ animation-timing-function: var(--mk-easing, ease-in-out);
139
+ animation-fill-mode: both;
140
+ }
141
+
142
+ /* ----- Preset classes ----- */
143
+ .mk-fade-in { animation-name: mk-fadeIn; }
144
+ .mk-fade-out { animation-name: mk-fadeOut; }
145
+ .mk-fade-in-linear { animation-name: mk-fadeInLinear; }
146
+ .mk-fade-out-linear { animation-name: mk-fadeOutLinear; }
147
+ .mk-fade-in-up { animation-name: mk-fadeInUp; }
148
+ .mk-fade-out-up { animation-name: mk-fadeOutUp; }
149
+ .mk-fade-in-down { animation-name: mk-fadeInDown; }
150
+ .mk-fade-out-down { animation-name: mk-fadeOutDown; }
151
+ .mk-fade-in-left { animation-name: mk-fadeInLeft; }
152
+ .mk-fade-out-left { animation-name: mk-fadeOutLeft; }
153
+ .mk-fade-in-right { animation-name: mk-fadeInRight; }
154
+ .mk-fade-out-right { animation-name: mk-fadeOutRight; }
155
+
156
+ .mk-zoom-in-center { animation-name: mk-zoomInCenter; }
157
+ .mk-zoom-out-center { animation-name: mk-zoomOutCenter; }
158
+ .mk-zoom-in-top { animation-name: mk-zoomInTop; }
159
+ .mk-zoom-out-top { animation-name: mk-zoomOutTop; }
160
+ .mk-zoom-in-bottom { animation-name: mk-zoomInBottom; }
161
+ .mk-zoom-out-bottom { animation-name: mk-zoomOutBottom; }
162
+
163
+ .mk-slide-in-right { animation-name: mk-slideInRight; }
164
+ .mk-slide-out-right { animation-name: mk-slideOutRight; }
165
+ .mk-slide-in-left { animation-name: mk-slideInLeft; }
166
+ .mk-slide-out-left { animation-name: mk-slideOutLeft; }
167
+ .mk-slide-in-top { animation-name: mk-slideInTop; }
168
+ .mk-slide-out-top { animation-name: mk-slideOutTop; }
169
+ .mk-slide-in-bottom { animation-name: mk-slideInBottom; }
170
+ .mk-slide-out-bottom { animation-name: mk-slideOutBottom; }
171
+
172
+ .mk-list-item-in { animation-name: mk-listItemIn; }
173
+
174
+ .mk-spin { animation: mk-spin 1s linear infinite; }