Skip to content

Commit 4d488ce

Browse files
zzcrlyra-planet
andauthored
feat(theme): add global animation configuration (#3843)
* feat(theme): [transition] add global animation configuration scheme (LESS-based) (#3632) * feat(theme): [transition] add global animation configuration scheme (LESS-based) * fix(tag): fix the index.less * feat(theme): [motion] add global animation variables * feat(theme): [motion] update the documentation and fix some bug * feat(theme): [motion] rename the documentation and remove unnecessary comments * feat(theme): [motion] reset the css variables * feat(theme): [motion] optimized animation effect configuration * feat(theme): [motion] rename configuration * feat(theme): [motion] fix problem in test:e2e * feat(theme): [motion] refine the configuration md (#3721) * Merge branch 'dev' of github.com:opentiny/tiny-vue into ospp-2025/tiny-vue-animation --------- Co-authored-by: Lyra <[email protected]>
1 parent e08a60e commit 4d488ce

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2087
-681
lines changed

examples/sites/demos/pc/app/scroll-text/scroll-direction.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { test, expect } from '@playwright/test'
33
test('文字滚动方向', async ({ page }) => {
44
page.on('pageerror', (exception) => expect(exception).toBeNull())
55
await page.goto('scroll-text#scroll-direction')
6-
await expect(page.locator('.tiny-scroll-text__content > div').nth(0)).toHaveCSS('animation-name', 'moveLeft')
7-
await expect(page.locator('.tiny-scroll-text__content > div').nth(1)).toHaveCSS('animation-name', 'moveRight')
8-
await expect(page.locator('.tiny-scroll-text__content > div').nth(2)).toHaveCSS('animation-name', 'moveUp')
9-
await expect(page.locator('.tiny-scroll-text__content > div').nth(3)).toHaveCSS('animation-name', 'moveDown')
6+
await expect(page.locator('.tiny-scroll-text__content > div').nth(0)).toHaveCSS('animation-name', 'scroll-left')
7+
await expect(page.locator('.tiny-scroll-text__content > div').nth(1)).toHaveCSS('animation-name', 'scroll-right')
8+
await expect(page.locator('.tiny-scroll-text__content > div').nth(2)).toHaveCSS('animation-name', 'scroll-up')
9+
await expect(page.locator('.tiny-scroll-text__content > div').nth(3)).toHaveCSS('animation-name', 'scroll-down')
1010
})

examples/sites/demos/pc/menus.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ const docMenusChildren = [
5353
theme: ['default']
5454
}
5555
},
56+
{
57+
'title': '全局动效配置',
58+
'titleEn': 'motion-configuration',
59+
'key': 'motion-configuration',
60+
showScene: {
61+
theme: ['default']
62+
}
63+
},
5664
{
5765
'title': '智能化',
5866
'titleEn': 'mcp',
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# TinyVue Global Motion Configuration
2+
3+
This solution provides **global motion configuration** for TinyVue, based on **LESS and CSS variables**, with the following goals:
4+
5+
1. **Unified Management**: All motions are centrally maintained to avoid scattered definitions and redundant work.
6+
2. **Global Control**: Use CSS variables to control motion duration, delay, speed, and other parameters.
7+
3. **Component Integration**: Components can directly use the unified motion class names or `@keyframes`.
8+
4. **Dynamic Adjustability**: Switch motion styles for different scenarios simply by overriding CSS variables.
9+
10+
## Global Configuration
11+
12+
### Global Variable Definition
13+
14+
Define motion variables in `/packages/theme/src/base/vars.less`:
15+
16+
```less
17+
:root {
18+
/* Ants (marching border) related config */
19+
--tv-motion-ants-shift: 8px;
20+
--tv-motion-ants-speed: 0.8s;
21+
22+
/* Other motion parameters... */
23+
}
24+
```
25+
26+
Developers can override these variables in the component theme file:
27+
28+
```css
29+
.copyed-borders {
30+
--tv-motion-ants-shift: 12px;
31+
--tv-motion-ants-speed: 1.2s;
32+
}
33+
```
34+
35+
Or create a `motion-theme.less` file under `/packages/theme/src/base/` to switch global motion styles:
36+
37+
```less
38+
:root {
39+
--tv-motion-ants-shift: 12px;
40+
--tv-motion-ants-speed: 1.2s;
41+
}
42+
```
43+
44+
## Motion Categories & Directory Structure
45+
46+
All motions are stored in `/packages/theme/src/motion/`, organized by type:
47+
48+
```
49+
motion/
50+
├─ fade.less // Fade in/out
51+
├─ slide.less // Slide
52+
├─ zoom.less // Zoom
53+
├─ rotate.less // Rotate
54+
├─ bounce.less // Bounce
55+
├─ scroll.less // Scroll
56+
├─ stroke.less // Stroke
57+
├─ shine.less // Shine
58+
├─ ants.less // Ants (marching border)
59+
├─ arrow.less // Arrow
60+
├─ tab.less // Tab switching
61+
├─ progress.less // Progress bar
62+
└─ index.less // Unified import
63+
```
64+
65+
## Motion Examples
66+
67+
### 1. Fade (fade.less)
68+
69+
```less
70+
@keyframes fade-in {
71+
0% { opacity: 0; }
72+
100% { opacity: 1; }
73+
}
74+
75+
@keyframes fade-out {
76+
0% { opacity: 1; }
77+
100% { opacity: 0; }
78+
}
79+
```
80+
81+
Component usage example:
82+
83+
```less
84+
.@{fade-prefix-cls} {
85+
&-enter-active {
86+
animation: var(--tv-motion-fade-speed) fade-in ease-out both;
87+
}
88+
&-leave-active {
89+
animation: var(--tv-motion-fade-speed) fade-out ease-in both;
90+
}
91+
}
92+
```
93+
94+
### 2. Slide (slide.less)
95+
96+
```less
97+
@keyframes slide-left-in {
98+
0% { opacity: 0; transform: translateX(var(--tv-motion-slide-offset-left)); }
99+
50% { opacity: var(--tv-motion-slide-opacity-mid); transform: translateX(var(--tv-motion-slide-offset-left-mid)); }
100+
100% { opacity: 1; transform: translateX(0%); }
101+
}
102+
103+
@keyframes slide-left-out {
104+
0% { opacity: 1; transform: translateX(0%); }
105+
50% { opacity: var(--tv-motion-slide-opacity-mid); transform: translateX(var(--tv-motion-slide-offset-left-mid)); }
106+
100% { opacity: 0; transform: translateX(var(--tv-motion-slide-offset-left)); }
107+
}
108+
```
109+
110+
Component usage example:
111+
112+
```less
113+
.drawer-slide-left-enter-active {
114+
animation: slide-left-in var(--tv-motion-slide-speed) linear;
115+
}
116+
.drawer-slide-left-leave-active {
117+
animation: slide-left-out var(--tv-motion-slide-speed) linear;
118+
}
119+
```
120+
121+
### 3. Ants (ants.less, configurable)
122+
123+
```less
124+
@keyframes ants-x {
125+
0% { background-position: 0 0; }
126+
100% { background-position: var(--tv-motion-ants-shift, 8px) 0; }
127+
}
128+
129+
@keyframes ants-x-rev {
130+
0% { background-position: 0 0; }
131+
100% { background-position: calc(-1 * var(--tv-motion-ants-shift, 8px)) 0; }
132+
}
133+
```
134+
135+
Component usage example:
136+
137+
```less
138+
.@{grid-prefix-cls}-copyed-borders {
139+
--tv-motion-ants-shift: 13px;
140+
141+
.@{grid-prefix-cls}-border-top {
142+
animation: ants-x var(--tv-motion-ants-speed) linear infinite;
143+
}
144+
.@{grid-prefix-cls}-border-right {
145+
animation: ants-y var(--tv-motion-ants-speed) linear infinite;
146+
}
147+
.@{grid-prefix-cls}-border-bottom {
148+
animation: ants-x-rev var(--tv-motion-ants-speed) linear infinite;
149+
}
150+
.@{grid-prefix-cls}-border-left {
151+
animation: ants-y-rev var(--tv-motion-ants-speed) linear infinite;
152+
}
153+
}
154+
```
155+
156+
## Component Integration
157+
158+
1. **Global Import**
159+
All `@keyframes` are maintained in `transition.less` and `motion/*`, and loaded together.
160+
161+
2. **Local Usage**
162+
Components can use the motions via `className` or `animation`.
163+
164+
3. **Configurable Parameters**
165+
Developers can override `:root` variables to adjust motion duration, speed, and other parameters.
166+
167+
## Extension & Maintenance
168+
169+
1. **Naming Convention**
170+
171+
* Use `{type}-{direction}-{state}` format, e.g., `slide-left-in`.
172+
* Ensure global uniqueness to avoid conflicts.
173+
174+
2. **Category Management**
175+
176+
* Motions must be written in the corresponding category file (e.g., slide → `slide.less`).
177+
* New variables must be declared in `index.less` first, then used in the specific file.
178+
179+
3. **Documentation & Comments**
180+
181+
* Each motion category should provide example code and usage instructions.
182+
* Add comments before `@keyframes` to indicate purpose and source.
183+
* Group related motions together for easier lookup and maintenance.
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# TinyVue 全局动效配置
2+
3+
为 TinyVue 提供 **全局动效配置能力**,基于 **LESS 与 CSS 变量**,实现以下目标:
4+
5+
1. **统一管理**:所有动效集中维护,避免分散定义与重复工作。
6+
2. **全局可控**:通过 CSS 变量统一控制动效的持续时间、延迟、速度等参数。
7+
3. **组件集成**:组件可直接调用统一的动效类名或 `@keyframes`
8+
4. **动态可调**:通过覆盖 CSS 变量即可在不同场景下切换动效风格。
9+
10+
## 全局配置
11+
12+
### 全局变量定义
13+
14+
`/packages/theme/src/base/vars.less` 中统一定义动效变量:
15+
16+
```less
17+
:root {
18+
/* 蚂蚁线相关配置 */
19+
--tv-motion-ants-shift: 8px;
20+
--tv-motion-ants-speed: 0.8s;
21+
22+
/* 其他动效参数... */
23+
}
24+
```
25+
26+
开发者可在组件主题文件中覆盖这些变量:
27+
28+
```css
29+
.copyed-borders {
30+
--tv-motion-ants-shift: 12px;
31+
--tv-motion-ants-speed: 1.2s;
32+
}
33+
```
34+
35+
也可通过在 `/packages/theme/src/base/` 下创建 `motion-theme.less` 来切换全局动效风格:
36+
37+
```less
38+
:root {
39+
--tv-motion-ants-shift: 12px;
40+
--tv-motion-ants-speed: 1.2s;
41+
}
42+
```
43+
44+
## 动效分类与目录结构
45+
46+
所有动效存放在 `/packages/theme/src/motion/` 目录下,按类型拆分:
47+
48+
```
49+
motion/
50+
├─ fade.less // 淡入淡出
51+
├─ slide.less // 滑动
52+
├─ zoom.less // 缩放
53+
├─ rotate.less // 旋转
54+
├─ bounce.less // 弹跳
55+
├─ scroll.less // 滚动
56+
├─ stroke.less // 描边
57+
├─ shine.less // 闪烁
58+
├─ ants.less // 蚂蚁线
59+
├─ arrow.less // 箭头
60+
├─ tab.less // Tab 切换
61+
├─ progress.less // 进度条
62+
└─ index.less // 统一引入
63+
```
64+
65+
## 动效示例
66+
67+
### 1. 淡入淡出 (fade.less)
68+
69+
```less
70+
@keyframes fade-in {
71+
0% { opacity: 0; }
72+
100% { opacity: 1; }
73+
}
74+
75+
@keyframes fade-out {
76+
0% { opacity: 1; }
77+
100% { opacity: 0; }
78+
}
79+
```
80+
81+
组件调用示例:
82+
83+
```less
84+
.@{fade-prefix-cls} {
85+
&-enter-active {
86+
animation: var(--tv-motion-fade-speed) fade-in ease-out both;
87+
}
88+
&-leave-active {
89+
animation: var(--tv-motion-fade-speed) fade-out ease-in both;
90+
}
91+
}
92+
```
93+
94+
### 2. 滑动 (slide.less)
95+
96+
```less
97+
@keyframes slide-left-in {
98+
0% { opacity: 0; transform: translateX(var(--tv-motion-slide-offset-left)); }
99+
50% { opacity: var(--tv-motion-slide-opacity-mid); transform: translateX(var(--tv-motion-slide-offset-left-mid)); }
100+
100% { opacity: 1; transform: translateX(0%); }
101+
}
102+
103+
@keyframes slide-left-out {
104+
0% { opacity: 1; transform: translateX(0%); }
105+
50% { opacity: var(--tv-motion-slide-opacity-mid); transform: translateX(var(--tv-motion-slide-offset-left-mid)); }
106+
100% { opacity: 0; transform: translateX(var(--tv-motion-slide-offset-left)); }
107+
}
108+
```
109+
110+
组件调用示例:
111+
112+
```less
113+
.drawer-slide-left-enter-active {
114+
animation: slide-left-in var(--tv-motion-slide-speed) linear;
115+
}
116+
.drawer-slide-left-leave-active {
117+
animation: slide-left-out var(--tv-motion-slide-speed) linear;
118+
}
119+
```
120+
121+
### 3. 蚂蚁线 (ants.less,可配置)
122+
123+
```less
124+
@keyframes ants-x {
125+
0% { background-position: 0 0; }
126+
100% { background-position: var(--tv-motion-ants-shift, 8px) 0; }
127+
}
128+
129+
@keyframes ants-x-rev {
130+
0% { background-position: 0 0; }
131+
100% { background-position: calc(-1 * var(--tv-motion-ants-shift, 8px)) 0; }
132+
}
133+
```
134+
135+
组件调用示例:
136+
137+
```less
138+
.@{grid-prefix-cls}-copyed-borders {
139+
--tv-motion-ants-shift: 13px;
140+
141+
.@{grid-prefix-cls}-border-top {
142+
animation: ants-x var(--tv-motion-ants-speed) linear infinite;
143+
}
144+
.@{grid-prefix-cls}-border-right {
145+
animation: ants-y var(--tv-motion-ants-speed) linear infinite;
146+
}
147+
.@{grid-prefix-cls}-border-bottom {
148+
animation: ants-x-rev var(--tv-motion-ants-speed) linear infinite;
149+
}
150+
.@{grid-prefix-cls}-border-left {
151+
animation: ants-y-rev var(--tv-motion-ants-speed) linear infinite;
152+
}
153+
}
154+
```
155+
156+
## 组件集成方式
157+
158+
1. **全局引入**
159+
所有 `@keyframes``transition.less``motion/*` 中集中维护,统一加载。
160+
161+
2. **局部调用**
162+
组件可通过 `className``animation` 调用指定动效。
163+
164+
3. **可配置参数**
165+
开发者可通过覆盖 `:root` 变量调整动效时长、速度等参数。
166+
167+
## 扩展与维护
168+
169+
1. **命名规范**
170+
171+
* 采用 `{type}-{direction}-{state}` 格式,例如 `slide-left-in`
172+
* 保证命名全局唯一,避免冲突。
173+
174+
2. **分类管理**
175+
176+
* 动效必须写在对应分类文件中(如滑动类 → `slide.less`)。
177+
* 新增变量需先在 `index.less` 中声明,再在具体文件中调用。
178+
179+
3. **文档与注释**
180+
181+
* 每类动效提供示例代码和调用方式说明。
182+
*`@keyframes` 前添加注释,标注用途和来源。
183+
* 同类动效按分组书写,便于快速查找与维护。

0 commit comments

Comments
 (0)