Skip to content

Commit 5fa6222

Browse files
committed
Merge remote-tracking branch 'origin/fix-drn-2.10.17' into fix-drn-2.10.17
2 parents c4d39b2 + df5fd80 commit 5fa6222

File tree

24 files changed

+1475
-352
lines changed

24 files changed

+1475
-352
lines changed

analyze_git_stats.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import subprocess
2+
import sys
3+
import argparse
4+
from collections import defaultdict
5+
from datetime import datetime
6+
7+
def analyze_git_stats():
8+
# Parse command line arguments
9+
parser = argparse.ArgumentParser(description='Analyze git contribution stats.')
10+
parser.add_argument('--since', type=str, default="1 year ago",
11+
help='Start time period to analyze (e.g. "1 year ago", "2023-01-01")')
12+
parser.add_argument('--until', type=str, default=None,
13+
help='End time period to analyze (e.g. "now", "1 month ago", "2024-01-01"). Defaults to now.')
14+
args = parser.parse_args()
15+
16+
# Configuration
17+
since_date = args.since
18+
until_date = args.until
19+
20+
# Author Alias Mapping
21+
# Format: 'Alias Name': 'Canonical Name'
22+
AUTHOR_MAPPINGS = {
23+
'wangshunnn': 'Soon Wang',
24+
'mackwang112': 'mackwang',
25+
'wangxiaokou': 'wangcuijuan',
26+
'dongxingxingdong': 'WX-DongXing',
27+
'yandadaFreedom': 'lareinayanyu'
28+
# Add more mappings here as needed
29+
}
30+
31+
# Using 'git log' to get the data
32+
# --numstat: shows added/deleted lines
33+
# --no-merges: optional, generally we want to count actual code contributions, not merge commits
34+
# --pretty=format:"AUTHOR:%aN": helps us identify who made the commit
35+
cmd = [
36+
"git", "log",
37+
f"--since={since_date}",
38+
"--numstat",
39+
"--pretty=format:AUTHOR:%aN",
40+
"--no-merges"
41+
]
42+
43+
if until_date:
44+
cmd.append(f"--until={until_date}")
45+
46+
try:
47+
# Run the command with utf-8 encoding errors ignored to prevent crashing on binary filenames or weird author names
48+
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, errors='replace')
49+
stdout, stderr = process.communicate()
50+
51+
if process.returncode != 0:
52+
print(f"Error executing git command: {stderr}")
53+
return
54+
55+
except FileNotFoundError:
56+
print("Error: 'git' command not found. Please ensure git is installed.")
57+
return
58+
59+
# Data structure:
60+
# stats = {
61+
# author: {
62+
# 'total': {'added': 0, 'deleted': 0, 'commits': 0},
63+
# 'lt_1000': {'added': 0, 'deleted': 0, 'commits': 0},
64+
# 'lt_5000': {'added': 0, 'deleted': 0, 'commits': 0}
65+
# }
66+
# }
67+
stats = defaultdict(lambda: {
68+
'total': {'added': 0, 'deleted': 0, 'commits': 0},
69+
'lt_1000': {'added': 0, 'deleted': 0, 'commits': 0},
70+
'lt_5000': {'added': 0, 'deleted': 0, 'commits': 0}
71+
})
72+
73+
lines = stdout.split('\n')
74+
75+
pending_author = None
76+
pending_commit_stats = {'added': 0, 'deleted': 0}
77+
78+
def finalize_commit(author, commit_stats):
79+
if not author:
80+
return
81+
82+
added = commit_stats['added']
83+
deleted = commit_stats['deleted']
84+
total_change = added + deleted
85+
86+
# Add to Total
87+
stats[author]['total']['added'] += added
88+
stats[author]['total']['deleted'] += deleted
89+
stats[author]['total']['commits'] += 1
90+
91+
# Add to < 5000
92+
if total_change < 5000:
93+
stats[author]['lt_5000']['added'] += added
94+
stats[author]['lt_5000']['deleted'] += deleted
95+
stats[author]['lt_5000']['commits'] += 1
96+
97+
# Add to < 1000
98+
if total_change < 1000:
99+
stats[author]['lt_1000']['added'] += added
100+
stats[author]['lt_1000']['deleted'] += deleted
101+
stats[author]['lt_1000']['commits'] += 1
102+
103+
for line in lines:
104+
line = line.strip()
105+
if not line:
106+
continue
107+
108+
if line.startswith("AUTHOR:"):
109+
# Finish previous commit
110+
finalize_commit(pending_author, pending_commit_stats)
111+
112+
# Start new commit
113+
raw_author = line.split("AUTHOR:", 1)[1].strip()
114+
pending_author = AUTHOR_MAPPINGS.get(raw_author, raw_author)
115+
pending_commit_stats = {'added': 0, 'deleted': 0}
116+
else:
117+
# It's a numstat line: "added deleted filepath"
118+
parts = line.split(maxsplit=2)
119+
if len(parts) == 3:
120+
added, deleted, _ = parts
121+
122+
# Handle binary files or other non-numeric entries
123+
if added == '-' or deleted == '-':
124+
continue
125+
126+
try:
127+
pending_commit_stats['added'] += int(added)
128+
pending_commit_stats['deleted'] += int(deleted)
129+
except ValueError:
130+
continue
131+
132+
# Finalize the last commit
133+
finalize_commit(pending_author, pending_commit_stats)
134+
135+
# Output formatting
136+
def print_table(title, key_type):
137+
print(f"\n{title}")
138+
print(f"{'Author':<30} | {'Added':<10} | {'Deleted':<10} | {'Total Lines':<12} | {'Commits':<8}")
139+
print("-" * 80)
140+
141+
# Convert to list for sorting
142+
results = []
143+
for author, data in stats.items():
144+
category_data = data[key_type]
145+
total_changed = category_data['added'] + category_data['deleted']
146+
# Only include if they have commits in this category
147+
if category_data['commits'] > 0:
148+
results.append({
149+
'author': author,
150+
'added': category_data['added'],
151+
'deleted': category_data['deleted'],
152+
'total': total_changed,
153+
'commits': category_data['commits']
154+
})
155+
156+
# Sort by total lines changed (descending)
157+
results.sort(key=lambda x: x['total'], reverse=True)
158+
159+
total_added_all = 0
160+
total_deleted_all = 0
161+
total_commits_all = 0
162+
163+
for r in results:
164+
print(f"{r['author']:<30} | {r['added']:<10} | {r['deleted']:<10} | {r['total']:<12} | {r['commits']:<8}")
165+
total_added_all += r['added']
166+
total_deleted_all += r['deleted']
167+
total_commits_all += r['commits']
168+
169+
print("-" * 80)
170+
print(f"{'TOTAL':<30} | {total_added_all:<10} | {total_deleted_all:<10} | {total_added_all+total_deleted_all:<12} | {total_commits_all:<8}")
171+
172+
print_table("=== ALL COMMITS ===", 'total')
173+
print_table("=== COMMITS < 5000 LINES ===", 'lt_5000')
174+
print_table("=== COMMITS < 1000 LINES ===", 'lt_1000')
175+
176+
if __name__ == "__main__":
177+
analyze_git_stats()

docs-vitepress/guide/rn/style.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,3 +1429,110 @@ object-fit: contain; /* 完整显示,保持比例 */
14291429
object-fit: cover; /* 覆盖填充,保持比例,可能裁剪 */
14301430
object-fit: scale-down; /* 缩小显示 */
14311431
```
1432+
1433+
1434+
## 跨端动画
1435+
基础组件 view 支持两种动画形式 createAnimation API 和 transition,
1436+
可以通过设置 animation 属于来使用 createAnimation API 动画,通过 class 或者 style 设置 css transition 来使用 transition 动画,
1437+
可以用过 prop enableAnimation = api/transition 来指定使用 createAnimation API/transition 的动画形式,,enableAnimation 设置 true 默认为 createAnimation API 形式,需要注意的是指定动画类型后,对应的动画参数也需要匹配设置,详细使用文档如下:
1438+
1439+
### createAnimation 动画API
1440+
创建一个动画实例 animation,调用实例的方法来描述动画,最后通过动画实例的 export 方法导出动画数据传递给组件的 animation 属性。
1441+
详情参考以下动画部分微信小程序文档,以下仅描述支持能力有差异部分:
1442+
#### [wx.createAnimation](https://developers.weixin.qq.com/miniprogram/dev/api/ui/animation/wx.createAnimation.html)
1443+
- 参数 timingFunction 不支持 step-start 和 step-end
1444+
#### [动画实例 animation](https://developers.weixin.qq.com/miniprogram/dev/api/ui/animation/Animation.html)
1445+
- translateZ() 不支持
1446+
- translate3d() 不支持
1447+
- rotate3d() 不支持
1448+
- rotateZ() 不支持
1449+
- scaleZ() 不支持
1450+
- scale3d() 不支持
1451+
- animation.matrix() 不支持
1452+
- animation.matrix3d() 不支持
1453+
1454+
### CSS transition
1455+
CSS transition 动画至少需要设置动画时长和动画属性,可通过单独属性 transition-property 和 transition-property 设置,也可以通过 transition 缩写设置
1456+
>重要提示:transition 支持设置百分比,如 ```marginTop: 1%;marginTop: 100%;```;要注意的是起始值和结束值需设置为同一类型,同为px或者同为百分比, 支持 ```marginTop: 10px;marginTop: 100px; ```**不支持 ```marginTop: 10px; marginTop: 100%;```**
1457+
1458+
#### [transition](https://developer.mozilla.org/en-US/docs/Web/CSS/transition)
1459+
```css
1460+
/**** 支持 */
1461+
/* property name | duration */
1462+
transition: margin-right 4s;
1463+
/* property name | duration | delay */
1464+
transition: margin-right 4s 1s;
1465+
/* property name | duration | easing function */
1466+
transition: margin-right 4s ease-in-out;
1467+
/* property name | duration | easing function | delay */
1468+
transition: margin-right 4s ease-in-out 1s;
1469+
1470+
/* Apply to 2 properties */
1471+
transition: margin-right 4s, color 1s;
1472+
```
1473+
```css
1474+
/**** 需配合 transition-property 使用*/
1475+
/* transition 未定义 property 时需配合 transition-property 使用,否则仅设置duration、timingFunciton等参数实际动画不生效 */
1476+
transition: 200ms linear 50ms;
1477+
transition: 2s, 1s;
1478+
```
1479+
```css
1480+
/**** 不支持:property 不支持设置为 all */
1481+
transition: all 0.5s ease-out
1482+
```
1483+
#### [transition-property](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-property)
1484+
不支持设置为 all,不支持自定义
1485+
> 支持的 property 合集有:
1486+
> rotateX rotateY rotateZ scaleX scaleY skewX skewY translateX translateY opacity backgroundColor width height top right bottom left color borderColor borderBottomColor borderLeftColor borderRightColor borderTopColor borderTopLeftRadius borderTopRightRadius borderBottomLeftRadius borderBottomRightRadius borderRadius borderBottomWidth borderLeftWidth borderRightWidth borderTopWidth borderWidth margin marginBottom marginLeft marginRight marginTop maxHeight maxWidth minHeight minWidth padding paddingBottom paddingLeft paddingRight paddingTop
1487+
```css
1488+
/**** 支持 */
1489+
transition-property: height;
1490+
transition-property: height, color;
1491+
```
1492+
```css
1493+
/**** 不支持 */
1494+
transition-property: all;
1495+
/* <custom-ident> values */
1496+
transition-property: test_05;
1497+
transition-property: -specific;
1498+
transition-property: sliding-vertically;
1499+
transition-property: test1, animation4;
1500+
transition-property: all, -moz-specific, sliding;
1501+
transition-property: inherit;
1502+
transition-property: initial;
1503+
transition-property: revert;
1504+
transition-property: revert-layer;
1505+
transition-property: unset;
1506+
```
1507+
#### [transition-duration](https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-duration)
1508+
```css
1509+
/**** 支持 */
1510+
transition-duration: 6s;
1511+
transition-duration: 120ms;
1512+
transition-duration: 1s, 15s;
1513+
transition-duration: 10s, 30s, 230ms;
1514+
```
1515+
#### [transition-delay](https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-delay)
1516+
```css
1517+
/**** 支持 */
1518+
transition-delay: 3s;
1519+
transition-delay: 2s, 4ms;
1520+
```
1521+
#### [transition-behavior](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior)
1522+
不支持
1523+
#### [transition-timing-function](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function)
1524+
仅支持 ease、ease-inease-outease-in-out、linear、cubic-bezier(),不支持 step-startstep-end、steps()
1525+
1526+
### CSS animation
1527+
暂不支持
1528+
1529+
### 动画监听事件
1530+
#### transitionend
1531+
- CSS transition 结束或 wx.createAnimation 结束一个阶段时触发
1532+
- 不属于冒泡事件,需要绑定在真正发生了动画的节点上才会生效
1533+
#### animationstart
1534+
暂不支持
1535+
#### animationiteration
1536+
暂不支持
1537+
#### animationend
1538+
暂不支持

packages/core/src/convertor/wxToWeb.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
diffAndCloneA,
77
error,
88
hasOwn,
9-
isDev
9+
isDev,
10+
getDefaultValueByType
1011
} from '@mpxjs/utils'
1112
import { implemented } from '../core/implement'
1213

@@ -56,6 +57,12 @@ export default {
5657
return diffAndCloneA(prop.value).clone
5758
}
5859
: prop.value
60+
} else {
61+
// 没有显式设置value时,根据type自动添加默认值,与微信小程序原生行为保持一致
62+
const defaultValue = getDefaultValueByType(prop.type, 'web')
63+
if (defaultValue !== undefined) {
64+
newProp.default = defaultValue
65+
}
5966
}
6067
props[key] = newProp
6168
} else {

packages/core/src/helper/MpxScroll/index.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ export default class MpxScroll {
5757
const isIntersecting = change.isIntersecting
5858
this.isIntersecting = isIntersecting
5959
if (!isIntersecting) {
60-
// 非 inter section 状态下及时清除 transtorm,以免影响正常滚动时元素的 fixed 定位
61-
this.el.style.cssText = ''
60+
// 非 inter section 状态下及时清除 transform,以免影响正常滚动时元素的 fixed 定位
61+
this.el.style.transform = ''
6262
this.pullDownEventRegister && this.pullDownEventRegister.destroy()
6363
} else {
6464
this.pullDownEventRegister = new EventRegister(this.el, [
@@ -103,7 +103,12 @@ export default class MpxScroll {
103103

104104
transformPage (distance) {
105105
this.translateY = distance
106-
this.el.style.cssText = `transform: translateY(${distance}px)`
106+
if (distance === 0) {
107+
// 距离为 0 时移除 transform,避免影响页面 fixed 定位
108+
this.el.style.transform = ''
109+
} else {
110+
this.el.style.transform = `translateY(${distance}px)`
111+
}
107112
}
108113

109114
onTouchEnd (e) {
@@ -219,8 +224,15 @@ export default class MpxScroll {
219224
}
220225

221226
onReachBottom (onReachBottomDistance, callback) {
222-
const { bottom } = this.el.getBoundingClientRect()
223-
const mark = bottom - window.innerHeight <= onReachBottomDistance
227+
const scrollTop = getScrollTop()
228+
const scrollHeight = document.documentElement.scrollHeight
229+
const clientHeight = window.innerHeight
230+
231+
// 使用 scrollHeight 判断实际内容高度是否超过视口,只有可滚动时才计算触底
232+
const scrollable = scrollHeight > clientHeight
233+
// 距离底部的距离 = 内容总高度 - (当前滚动位置 + 视口高度)
234+
const distanceToBottom = scrollHeight - (scrollTop + clientHeight)
235+
const mark = scrollable && (distanceToBottom <= onReachBottomDistance)
224236

225237
if (!this.bottomReached && mark) {
226238
this.bottomReached = true

packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export default function styleHelperMixin () {
267267
classString.split(/\s+/).forEach((className) => {
268268
let localStyle, appStyle
269269
const getAppClassStyle = global.__getAppClassStyle || noop
270-
if (localStyle = this.__getClassStyle(className)) {
270+
if (localStyle = this.__getClassStyle?.(className)) {
271271
if (localStyle._media?.length) {
272272
mergeResult(localStyle._default, getMediaStyle(localStyle._media))
273273
} else {

packages/core/src/platform/patch/getDefaultOptions.ios.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as ReactNative from 'react-native'
33
import { ReactiveEffect } from '../../observer/effect'
44
import { watch } from '../../observer/watch'
55
import { del, reactive, set } from '../../observer/reactive'
6-
import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, dash2hump, callWithErrorHandling, wrapMethodsWithErrorHandling, error, setFocusedNavigation } from '@mpxjs/utils'
6+
import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, dash2hump, callWithErrorHandling, wrapMethodsWithErrorHandling, error, setFocusedNavigation, getDefaultValueByType } from '@mpxjs/utils'
77
import MpxProxy from '../../core/proxy'
88
import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../core/innerLifecycle'
99
import mergeOptions from '../../core/mergeOptions'
@@ -172,8 +172,8 @@ const instanceProto = {
172172
type: field
173173
}
174174
}
175-
// 处理props默认值
176-
propsData[key] = field.value
175+
// 处理props默认值,没有显式设置value时根据type获取默认值,与微信小程序原生行为保持一致
176+
propsData[key] = hasOwn(field, 'value') ? field.value : getDefaultValueByType(field.type)
177177
}
178178
}
179179
})

0 commit comments

Comments
 (0)