uview-plus 3.8.127 → 3.8.128

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 (65) hide show
  1. package/README.md +13 -0
  2. package/changelog.md +29 -0
  3. package/components/u-calendar/month.vue +71 -35
  4. package/components/u-calendar/u-calendar.vue +67 -31
  5. package/components/u-car-keyboard/u-car-keyboard.vue +21 -8
  6. package/components/u-cate-tab/u-cate-tab.vue +56 -11
  7. package/components/u-cell/u-cell.vue +20 -16
  8. package/components/u-collapse-item/u-collapse-item.vue +34 -11
  9. package/components/u-datetime-picker/u-datetime-picker.vue +16 -0
  10. package/components/u-dropdown/u-dropdown.vue +15 -0
  11. package/components/u-grid/u-grid.vue +9 -0
  12. package/components/u-grid-item/u-grid-item.vue +8 -0
  13. package/components/u-icon/util.js +16 -1
  14. package/components/u-list/u-list.vue +59 -8
  15. package/components/u-list-item/u-list-item.vue +9 -3
  16. package/components/u-number-keyboard/u-number-keyboard.vue +18 -6
  17. package/components/u-parse/parser.js +4 -3
  18. package/components/u-picker/u-picker.vue +6 -3
  19. package/components/u-search/u-search.vue +15 -5
  20. package/components/u-select/u-select.vue +206 -31
  21. package/components/u-slider/u-slider.vue +21 -12
  22. package/components/u-tabs/u-tabs.vue +5 -1
  23. package/components/u-text/u-text.vue +34 -32
  24. package/components/u-textarea/props.js +5 -0
  25. package/components/u-textarea/textarea.js +4 -1
  26. package/components/u-textarea/u-textarea.vue +3 -1
  27. package/components/u-upload/u-upload.vue +15 -4
  28. package/components/u-upload/utils.js +4 -1
  29. package/components/u-video/danmaku.js +97 -0
  30. package/components/u-video/props.js +205 -0
  31. package/components/u-video/u-video.vue +1427 -0
  32. package/components/u-video/video-danmaku.vue +273 -0
  33. package/components/u-video/video-slider.vue +179 -0
  34. package/components/u-video/video-utils.js +98 -0
  35. package/components/u-video/video.js +72 -0
  36. package/libs/config/props.js +2 -1
  37. package/libs/function/test.js +2 -0
  38. package/libs/i18n/locales/de.js +14 -1
  39. package/libs/i18n/locales/en.js +14 -1
  40. package/libs/i18n/locales/es.js +14 -1
  41. package/libs/i18n/locales/fr.js +14 -1
  42. package/libs/i18n/locales/ja.js +14 -1
  43. package/libs/i18n/locales/ko.js +14 -1
  44. package/libs/i18n/locales/ru.js +14 -1
  45. package/libs/i18n/locales/th.js +14 -1
  46. package/libs/i18n/locales/zh-Hans.js +14 -1
  47. package/libs/i18n/locales/zh-Hant.js +14 -1
  48. package/libs/mixin/mixin.js +11 -6
  49. package/package.json +1 -1
  50. package/skills/README.md +66 -0
  51. package/skills/uview-plus/SKILL.md +95 -0
  52. package/skills/uview-plus/references/api.md +105 -0
  53. package/skills/uview-plus/references/components.md +156 -0
  54. package/skills/uview-plus/references/icons.md +223 -0
  55. package/skills/uview-plus/references/pitfalls.md +77 -0
  56. package/skills/uview-plus/references/setup.md +168 -0
  57. package/types/comps/form.d.ts +44 -8
  58. package/types/comps/list.d.ts +1 -1
  59. package/types/comps/listItem.d.ts +1 -1
  60. package/types/comps/numberBox.d.ts +85 -21
  61. package/types/comps/pagination.d.ts +96 -0
  62. package/types/comps/swipeActionItem.d.ts +3 -4
  63. package/types/comps/textarea.d.ts +9 -3
  64. package/types/comps.d.ts +1 -0
  65. package/types/index.d.ts +5 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * u-video 弹幕引擎的纯逻辑部分(归一化、时间游标、轨道分配)。
3
+ * 与 video-utils.js 一样不引入 uni / vue,方便 Node 端直接做行为断言。
4
+ */
5
+
6
+ // 同一轨道上两条弹幕之间的最小像素间隔
7
+ const TRACK_GAP = 20
8
+
9
+ const DANMU_TYPES = ['scroll', 'top', 'bottom']
10
+
11
+ export function normalizeDanmuItem(item) {
12
+ const danmu = typeof item === 'string' ? { text: item } : (item || {})
13
+ const time = Number(danmu.time)
14
+ return {
15
+ text: danmu.text === undefined || danmu.text === null ? '' : String(danmu.text),
16
+ color: danmu.color || '',
17
+ time: Number.isFinite(time) && time > 0 ? time : 0,
18
+ type: DANMU_TYPES.includes(danmu.type) ? danmu.type : 'scroll'
19
+ }
20
+ }
21
+
22
+ // 按出现时间升序排列,播放过程中只需要向后推进游标
23
+ export function normalizeDanmuList(list) {
24
+ if (!Array.isArray(list)) return []
25
+ return list
26
+ .map(normalizeDanmuItem)
27
+ .filter((item) => item.text !== '')
28
+ .sort((a, b) => a.time - b.time)
29
+ }
30
+
31
+ // 二分查找第一条「时间点不早于 time」的弹幕,拖动进度条后用它重置游标
32
+ export function findDanmuCursor(list, time) {
33
+ if (!Array.isArray(list) || !list.length) return 0
34
+ const target = Number(time)
35
+ let low = 0
36
+ let high = list.length
37
+ while (low < high) {
38
+ const middle = (low + high) >> 1
39
+ if (list[middle].time < target) {
40
+ low = middle + 1
41
+ } else {
42
+ high = middle
43
+ }
44
+ }
45
+ return low
46
+ }
47
+
48
+ // 粗略估算弹幕宽度:中文按一个字宽,其余按 0.55 字宽
49
+ export function estimateDanmuWidth(text, fontSize) {
50
+ const size = Number(fontSize) > 0 ? Number(fontSize) : 14
51
+ const content = String(text === undefined || text === null ? '' : text)
52
+ let units = 0
53
+ for (const char of content) {
54
+ units += char.charCodeAt(0) > 0x2e80 ? 1 : 0.55
55
+ }
56
+ return Math.ceil(units * size) + size
57
+ }
58
+
59
+ export function createDanmuState() {
60
+ return { tracks: [] }
61
+ }
62
+
63
+ export function resetDanmuState(state) {
64
+ if (state) state.tracks = []
65
+ return state
66
+ }
67
+
68
+ /**
69
+ * 取一条空闲轨道,全部占用时返回 -1(该条弹幕直接丢弃)。
70
+ * 滚动弹幕在尾巴完全进场后即可复用轨道;hold 用于顶/底部固定弹幕。
71
+ */
72
+ export function acquireDanmuTrack(state, options = {}) {
73
+ const {
74
+ now = 0,
75
+ itemWidth = 0,
76
+ containerWidth = 0,
77
+ duration = 8,
78
+ trackCount = 1,
79
+ hold = 0
80
+ } = options
81
+ if (!state) return -1
82
+ const total = Math.max(1, Math.floor(trackCount))
83
+ let busyFor = Number(hold)
84
+ if (!Number.isFinite(busyFor) || busyFor <= 0) {
85
+ const distance = Number(containerWidth) + Number(itemWidth)
86
+ const speed = distance > 0 ? distance / (Number(duration) * 1000) : 0
87
+ busyFor = speed > 0 ? (Number(itemWidth) + TRACK_GAP) / speed : 0
88
+ }
89
+ for (let index = 0; index < total; index++) {
90
+ const freeAt = state.tracks[index]
91
+ if (freeAt === undefined || now >= freeAt) {
92
+ state.tracks[index] = now + busyFor
93
+ return index
94
+ }
95
+ }
96
+ return -1
97
+ }
@@ -0,0 +1,205 @@
1
+ import { defineMixin } from '../../libs/vue'
2
+ import { registerComponentProps } from '../../libs/config/props.js'
3
+ import VideoDefaultProps from './video'
4
+
5
+ const defProps = registerComponentProps(VideoDefaultProps)
6
+
7
+ export const props = defineMixin({
8
+ props: {
9
+ // 视频地址,传了 episodes 时作为兜底地址
10
+ src: {
11
+ type: String,
12
+ default: () => defProps.video.src
13
+ },
14
+ // 封面图
15
+ poster: {
16
+ type: String,
17
+ default: () => defProps.video.poster
18
+ },
19
+ title: {
20
+ type: String,
21
+ default: () => defProps.video.title
22
+ },
23
+ width: {
24
+ type: [String, Number],
25
+ default: () => defProps.video.width
26
+ },
27
+ height: {
28
+ type: [String, Number],
29
+ default: () => defProps.video.height
30
+ },
31
+ radius: {
32
+ type: [String, Number],
33
+ default: () => defProps.video.radius
34
+ },
35
+ objectFit: {
36
+ type: String,
37
+ default: () => defProps.video.objectFit
38
+ },
39
+ autoplay: {
40
+ type: Boolean,
41
+ default: () => defProps.video.autoplay
42
+ },
43
+ loop: {
44
+ type: Boolean,
45
+ default: () => defProps.video.loop
46
+ },
47
+ muted: {
48
+ type: Boolean,
49
+ default: () => defProps.video.muted
50
+ },
51
+ initialTime: {
52
+ type: [String, Number],
53
+ default: () => defProps.video.initialTime
54
+ },
55
+ // 自绘控制层总开关
56
+ controls: {
57
+ type: Boolean,
58
+ default: () => defProps.video.controls
59
+ },
60
+ showCenterPlayBtn: {
61
+ type: Boolean,
62
+ default: () => defProps.video.showCenterPlayBtn
63
+ },
64
+ showFullscreenBtn: {
65
+ type: Boolean,
66
+ default: () => defProps.video.showFullscreenBtn
67
+ },
68
+ showBack: {
69
+ type: Boolean,
70
+ default: () => defProps.video.showBack
71
+ },
72
+ backIcon: {
73
+ type: String,
74
+ default: () => defProps.video.backIcon
75
+ },
76
+ autoHide: {
77
+ type: [String, Number],
78
+ default: () => defProps.video.autoHide
79
+ },
80
+ showLock: {
81
+ type: Boolean,
82
+ default: () => defProps.video.showLock
83
+ },
84
+ // 倍速
85
+ showRate: {
86
+ type: Boolean,
87
+ default: () => defProps.video.showRate
88
+ },
89
+ rate: {
90
+ type: [String, Number],
91
+ default: () => defProps.video.rate
92
+ },
93
+ rateList: {
94
+ type: Array,
95
+ default: () => defProps.video.rateList
96
+ },
97
+ // 音量
98
+ showVolume: {
99
+ type: Boolean,
100
+ default: () => defProps.video.showVolume
101
+ },
102
+ volume: {
103
+ type: [String, Number],
104
+ default: () => defProps.video.volume
105
+ },
106
+ // 弹幕
107
+ enableDanmu: {
108
+ type: Boolean,
109
+ default: () => defProps.video.enableDanmu
110
+ },
111
+ danmuList: {
112
+ type: Array,
113
+ default: () => defProps.video.danmuList
114
+ },
115
+ danmuBtn: {
116
+ type: Boolean,
117
+ default: () => defProps.video.danmuBtn
118
+ },
119
+ danmuOpen: {
120
+ type: Boolean,
121
+ default: () => defProps.video.danmuOpen
122
+ },
123
+ danmuColor: {
124
+ type: String,
125
+ default: () => defProps.video.danmuColor
126
+ },
127
+ danmuFontSize: {
128
+ type: [String, Number],
129
+ default: () => defProps.video.danmuFontSize
130
+ },
131
+ danmuDuration: {
132
+ type: [String, Number],
133
+ default: () => defProps.video.danmuDuration
134
+ },
135
+ danmuArea: {
136
+ type: String,
137
+ default: () => defProps.video.danmuArea
138
+ },
139
+ danmuOpacity: {
140
+ type: [String, Number],
141
+ default: () => defProps.video.danmuOpacity
142
+ },
143
+ danmuMax: {
144
+ type: [String, Number],
145
+ default: () => defProps.video.danmuMax
146
+ },
147
+ // 选集
148
+ episodes: {
149
+ type: Array,
150
+ default: () => defProps.video.episodes
151
+ },
152
+ episodeIndex: {
153
+ type: [String, Number],
154
+ default: () => defProps.video.episodeIndex
155
+ },
156
+ episodeColumns: {
157
+ type: [String, Number],
158
+ default: () => defProps.video.episodeColumns
159
+ },
160
+ autoNext: {
161
+ type: Boolean,
162
+ default: () => defProps.video.autoNext
163
+ },
164
+ // 广告
165
+ ads: {
166
+ type: Array,
167
+ default: () => defProps.video.ads
168
+ },
169
+ // 原生手势
170
+ enableProgressGesture: {
171
+ type: Boolean,
172
+ default: () => defProps.video.enableProgressGesture
173
+ },
174
+ pageGesture: {
175
+ type: Boolean,
176
+ default: () => defProps.video.pageGesture
177
+ },
178
+ vslideGesture: {
179
+ type: Boolean,
180
+ default: () => defProps.video.vslideGesture
181
+ },
182
+ direction: {
183
+ type: [String, Number],
184
+ default: () => defProps.video.direction
185
+ },
186
+ autoPauseIfNavigate: {
187
+ type: Boolean,
188
+ default: () => defProps.video.autoPauseIfNavigate
189
+ },
190
+ autoPauseIfOpenNative: {
191
+ type: Boolean,
192
+ default: () => defProps.video.autoPauseIfOpenNative
193
+ },
194
+ videoId: {
195
+ type: String,
196
+ default: () => defProps.video.videoId
197
+ },
198
+ activeColor: {
199
+ type: String,
200
+ default: () => defProps.video.activeColor
201
+ }
202
+ }
203
+ })
204
+
205
+ export default props