pixuireactcomponents 1.0.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.
Files changed (44) hide show
  1. package/package.json +11 -0
  2. package/ui/components/bulletscreen/BulletItemAnimation.tsx +117 -0
  3. package/ui/components/bulletscreen/BulletScreenAnimation.tsx +278 -0
  4. package/ui/components/bulletscreen/bullet.less +17 -0
  5. package/ui/components/dropdown/Dropdown.tsx +115 -0
  6. package/ui/components/dropdown/DropdownOptionUI.tsx +13 -0
  7. package/ui/components/dropdown/DropdownSpreadMainUI.tsx +11 -0
  8. package/ui/components/dropdown/DropdownUnspreadMainUI.tsx +11 -0
  9. package/ui/components/progress/Progress.tsx +166 -0
  10. package/ui/components/tab/Tab.tsx +12 -0
  11. package/ui/components/tab/Tabs.tsx +56 -0
  12. package/ui/components/videoplayer/VideoPlayer.tsx +200 -0
  13. package/ui/sample/Images.tsx +34 -0
  14. package/ui/sample/asset/data_arrow_down.png +0 -0
  15. package/ui/sample/asset/data_arrow_up.png +0 -0
  16. package/ui/sample/asset/dot.png +0 -0
  17. package/ui/sample/asset/inner.png +0 -0
  18. package/ui/sample/asset/item_reddot.png +0 -0
  19. package/ui/sample/asset/loading.png +0 -0
  20. package/ui/sample/asset/money_dropdown.png +0 -0
  21. package/ui/sample/asset/money_dropdownall.png +0 -0
  22. package/ui/sample/asset/outer.png +0 -0
  23. package/ui/sample/asset/tab_choosed.png +0 -0
  24. package/ui/sample/asset/tabs_bg.png +0 -0
  25. package/ui/sample/asset/video_pause.png +0 -0
  26. package/ui/sample/asset/video_play.png +0 -0
  27. package/ui/sample/asset/video_reload.png +0 -0
  28. package/ui/sample/bulletscreen/BulletDemo.tsx +86 -0
  29. package/ui/sample/dropdown/DropdownDemo.tsx +65 -0
  30. package/ui/sample/dropdown/MoneyDropdownOption.tsx +49 -0
  31. package/ui/sample/dropdown/MoneyDropdownSpreadMain.tsx +42 -0
  32. package/ui/sample/dropdown/MoneyDropdownUnspreadMain.tsx +44 -0
  33. package/ui/sample/less/video.less +143 -0
  34. package/ui/sample/progress/ProgressDemo.tsx +74 -0
  35. package/ui/sample/tab/TabDemo.tsx +67 -0
  36. package/ui/sample/tab/TopTab.tsx +74 -0
  37. package/ui/sample/videoplayer/VideoPlayerDemo.tsx +57 -0
  38. package/utils/EventDispatcherJs.tsx +74 -0
  39. package/utils/GenerateConstructorAndGeterSeter.js +223 -0
  40. package/utils/Logger.tsx +158 -0
  41. package/utils/MakeImage.js +204 -0
  42. package/utils/img/logger.png +0 -0
  43. package/utils/img/makeImage.png +0 -0
  44. package/utils/utils.md +145 -0
package/package.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "pixuireactcomponents",
3
+ "version": "1.0.0",
4
+ "description": "pixui react components",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "author": "hardenzheng",
10
+ "license": "ISC"
11
+ }
@@ -0,0 +1,117 @@
1
+ import { createRef } from "lib/preact/src/create-element";
2
+ import { Component, CSSProperties } from "preact";
3
+
4
+ // 弹幕相关个性化信息
5
+ export class BulletInfo{
6
+ key : number;
7
+ text : string;
8
+ channel : number;
9
+ color: string;
10
+ fontSize: number;
11
+
12
+ constructor(
13
+ key : number,
14
+ text : string,
15
+ channel :number,
16
+ color: string,
17
+ fontSize: number
18
+ ){
19
+ this.key = key;
20
+ this.text = text;
21
+ this.channel = channel;
22
+ this.color = color;
23
+ this.fontSize = fontSize;
24
+ }
25
+ }
26
+
27
+ // 同一行弹幕的间距
28
+ const BULLET_DISTANCE = 50
29
+ // 弹幕超出屏幕后滑行距离
30
+ const BULLET_MAX_LEN = 400
31
+
32
+ // 弹幕相关配置信息
33
+ export class BulletConfig{
34
+ screenWidth : number; //弹幕宽度
35
+ channelHeight : number; //弹幕高度
36
+ totalTime : number; //单条弹幕滑行时间
37
+
38
+ constructor(
39
+ screenWidth: number,
40
+ channelHeight: number,
41
+ totalTime :number
42
+ ){
43
+ this.screenWidth = screenWidth;
44
+ this.channelHeight = channelHeight;
45
+ this.totalTime = totalTime;
46
+ }
47
+ }
48
+
49
+ // 使用Animation
50
+ export class BulletItemAnimation extends Component<
51
+ {
52
+ bulletInfo: BulletInfo,
53
+ bulletConfig: BulletConfig,
54
+ onItemFree : Function,
55
+ onChannelFree : Function
56
+ }, {}>{
57
+
58
+ private freeChannelTimer : any = undefined;
59
+ private refText = createRef()
60
+
61
+ constructor(props){
62
+ super(props);
63
+ }
64
+
65
+ componentDidMount(){
66
+ this.refText.current.addEventListener("animationstart", this.onAnimationStart)
67
+ this.refText.current.addEventListener("animationend", this.onAnimationEnd)
68
+
69
+ window.requestAnimationFrame(this.setFreeChannelTimer);
70
+ }
71
+
72
+ onAnimationStart = ()=>{
73
+ }
74
+
75
+ onAnimationEnd = ()=>{
76
+ this.props.onItemFree();
77
+ }
78
+
79
+ setFreeChannelTimer = ()=>{
80
+ let realWidthStr = window.getComputedStyle(this.refText.current, null).getPropertyValue("width");
81
+ let widthNum = parseInt(realWidthStr.substring(0, realWidthStr.length - 2));
82
+ this.freeChannelTimer = setTimeout(this.freeChannel, (widthNum + BULLET_DISTANCE) / (this.props.bulletConfig.screenWidth + BULLET_MAX_LEN) * this.props.bulletConfig.totalTime);
83
+ }
84
+
85
+ freeChannel = ()=>{
86
+ this.props.onChannelFree(this.props.bulletInfo.channel);
87
+ clearTimeout(this.freeChannelTimer);
88
+ }
89
+
90
+ render(){
91
+
92
+ let isMe = false
93
+
94
+ const bulletStyle : CSSProperties = {
95
+ marginTop : (this.props.bulletInfo.channel * this.props.bulletConfig.channelHeight) + "px",
96
+ height: this.props.bulletConfig.channelHeight + 'px',
97
+ left: this.props.bulletConfig.screenWidth + "px",
98
+ animation: 'bulletKeyframe 10s linear 1',
99
+
100
+ position: 'absolute',
101
+ display: 'flex',
102
+ flexDirection: 'row',
103
+ justifyContent: 'flex-start',
104
+ alignItems: 'center',
105
+ border: isMe ? '1px solid ' + this.props.bulletInfo.color : '',
106
+
107
+ fontSize: this.props.bulletInfo.fontSize + "px", //'16px',
108
+ color: this.props.bulletInfo.color,
109
+ }
110
+
111
+ return(
112
+ <div ref={this.refText} style={bulletStyle}>
113
+ <text>{this.props.bulletInfo.text}</text>
114
+ </div>
115
+ );
116
+ }
117
+ }
@@ -0,0 +1,278 @@
1
+ import { Component, CSSProperties } from "preact";
2
+ import { Logger } from "src/pixUIReactComponents/utils/Logger";
3
+ import { BulletInfo, BulletConfig, BulletItemAnimation } from "./BulletItemAnimation";
4
+
5
+ // item数据类型
6
+ // {
7
+ // key : number,
8
+ // value : '人闲桂花落', string
9
+ // channel : number
10
+ // }
11
+ let bulletDataList: Array<BulletInfo> = [];
12
+
13
+ // 弹幕组件相关初始化信息
14
+ export class BulletScreenAnimationData{
15
+ generateCycle : number; //弹幕生成的周期
16
+ channelHeight : number; //每行弹幕的高度
17
+ screenWidth : number; //弹幕区域宽度
18
+ screenHeight : number; //弹幕区域高度
19
+ totalTime : number; //单条弹幕的滑行时间 单位ms
20
+
21
+ constructor(
22
+ generateCycle:number,
23
+ channelHeight : number,
24
+ screenWidth : number,
25
+ screenHeight: number,
26
+ totalTime : number
27
+ ){
28
+ this.generateCycle = generateCycle;
29
+ this.channelHeight = channelHeight;
30
+ this.screenWidth = screenWidth;
31
+ this.screenHeight = screenHeight;
32
+ this.totalTime = totalTime;
33
+ }
34
+ }
35
+
36
+
37
+ // 使用Animaiton
38
+ export class BulletScreenAnimation extends Component<
39
+ {
40
+ screenData : BulletScreenAnimationData,
41
+ getBulletText : Function,
42
+ isRun: boolean, //暂停生产弹幕,
43
+ screenWidth: number,
44
+ screenHeight: number,
45
+ },
46
+ {
47
+ refreshIndex : number,
48
+ }>{
49
+
50
+ private positionSize: number = 0;
51
+ private hasPosition : Array<boolean> = [];
52
+
53
+ private bulletIndex : number = 0;
54
+ private consumeBulletTimer : any = undefined;
55
+ private isStart: boolean = false; //弹幕是否开始播放
56
+ private isScreenSizeChanging = false; // 弹幕屏幕尺寸是否在改变中
57
+
58
+ constructor(props){
59
+ super(props);
60
+ this.setState({
61
+ refreshIndex: 0
62
+ })
63
+
64
+ this.initChannels();
65
+
66
+ this.consumeBulletTimer = setInterval(()=>{
67
+ let curChannel = -1;
68
+ if((curChannel = this.getChannel()) != -1){
69
+ if(!this.isStart) return
70
+ if(this.isScreenSizeChanging) return
71
+
72
+ let bulletText = this.props.getBulletText();
73
+ if(bulletText == undefined) return; //没有弹幕
74
+
75
+ if(!this.props.isRun) return; //弹幕开关关闭
76
+
77
+ bulletDataList.push(this.generateNewBulletInfo(bulletText, curChannel));
78
+ this.hasPosition[curChannel] = false;
79
+
80
+ let newIndex = this.state.refreshIndex + 1;
81
+ this.setState({
82
+ refreshIndex : newIndex
83
+ })
84
+
85
+ }
86
+ }, this.props.screenData.generateCycle);
87
+ }
88
+
89
+ generateNewBulletInfo = (text, channel)=>{
90
+ let _fontSize = 20
91
+ let _transparencyPercent = 0
92
+ // console.warn("_________________fontSize:", _fontSize)
93
+ let _color = `rgba(255,255,255,${1 - _transparencyPercent / 100})`
94
+ return new BulletInfo(this.bulletIndex++, text, channel, _color, _fontSize)
95
+ }
96
+
97
+ componentWillUnmount(){
98
+ if(this.consumeBulletTimer != undefined){
99
+ clearInterval(this.consumeBulletTimer);
100
+ this.consumeBulletTimer = undefined;
101
+ }
102
+ }
103
+
104
+ // 首字母大写表示可供外部调用
105
+ // 开始播放弹幕
106
+ StartRunBullets = ()=>{
107
+ this.isStart = true
108
+ }
109
+
110
+ // 停止播放弹幕
111
+ StopRunBullets = ()=>{
112
+ this.isStart = false
113
+ }
114
+
115
+ // 清空屏幕上的弹幕
116
+ ClearScreenBullets = ()=>{
117
+ bulletDataList = []
118
+ this.initChannels()
119
+
120
+ let newIndex = this.state.refreshIndex + 1;
121
+ this.setState({
122
+ refreshIndex : newIndex
123
+ })
124
+ }
125
+
126
+ SetScreenSizeChanging = ()=>{
127
+ this.isScreenSizeChanging = true
128
+ }
129
+
130
+ setScreenSizeChanged = ()=>{
131
+ this.isScreenSizeChanging = false
132
+ }
133
+
134
+ componentWillReceiveProps(nextProps){
135
+ // Logger.ObjectPrinter(nextProps, "# nextProps #")
136
+ if(this.isScreenSizeSame(this.props, nextProps)) return
137
+
138
+ console.log("ScreenSizeChanged, generate new Animation!!!============")
139
+ Logger.ObjectPrinter(nextProps, "# nextProps #")
140
+
141
+ this.generateTargetAnimation(nextProps)
142
+ this.initChannels(nextProps)
143
+ this.setScreenSizeChanged()
144
+ }
145
+
146
+ generateTargetAnimation = (currentProps)=>{
147
+ this.generateDynamicAnimation("bulletKeyframe",
148
+ `from{
149
+ left: ${currentProps.screenWidth}px
150
+ }
151
+ to{
152
+ left: -400px;
153
+ }`
154
+ )
155
+ }
156
+
157
+ isScreenSizeSame = (oldProps, newProps)=>{
158
+ if(oldProps.screenWidth == newProps.screenWidth &&
159
+ oldProps.screenHeight == newProps.screenHeight){
160
+ return true
161
+ }
162
+ return false
163
+ }
164
+
165
+ generateDynamicAnimation = (name, styles)=>{
166
+ console.log("&&&&&&&&&&&&&&&&&&&&&&=====================================")
167
+
168
+ var css = `@keyframes ${name}{${styles}}`
169
+ let head = document.getElementsByTagName('head')[0]
170
+ let style: any = document.createElement('style');
171
+ style.type = 'text/css';
172
+ if(style.styleSheet){
173
+ style.styleSheet.cssText = css;
174
+ }else{
175
+ style.appendChild(document.createTextNode(css));
176
+ }
177
+ head.appendChild(style);
178
+ }
179
+
180
+ initChannels(currentProps = this.props){
181
+ this.positionSize = Math.floor(currentProps.screenHeight / currentProps.screenData.channelHeight)
182
+ this.hasPosition = [];
183
+
184
+ //初始化 所有信道当前可用;每个信道都有一个缓存池;
185
+ for (let index = 0; index < this.positionSize; index++) {
186
+ this.hasPosition[index] = true;
187
+ }
188
+ console.warn("position:", this.hasPosition.length)
189
+ }
190
+
191
+ //先尝试随机取3次位置,取不到可用位置就从头开始遍历位置
192
+ getChannel = ()=>{
193
+ let tryCount = 3;
194
+
195
+ while(tryCount > 0){
196
+ let channel = this.getRandomChannelByPosition();
197
+ if(this.hasPosition[channel]){
198
+ return channel;
199
+ }
200
+ tryCount--;
201
+ }
202
+
203
+ return this.getAvailableChannelByPosition()
204
+ }
205
+
206
+ getRandomChannelByPosition = ()=>{
207
+ // 根据position 配置,决定随机的位置
208
+ let _random
209
+ // if(Settings.bulletSettings.position == BulletPositon.TopHalf){
210
+ // let _topHalfsize = Math.floor(this.positionSize / 2)
211
+ // _random = Math.random() * _topHalfsize
212
+ // }
213
+ // else if(Settings.bulletSettings.position == BulletPositon.BottomHalf){
214
+ // let _topHalfsize = Math.floor(this.positionSize / 2)
215
+ // _random = Math.random() * (this.positionSize - _topHalfsize) + _topHalfsize
216
+ // }
217
+ // else{ //Settings.bulletSettings.position == BulletPositon.Full
218
+ _random = Math.random() * this.positionSize
219
+ // }
220
+
221
+ return Math.floor(_random)
222
+ }
223
+
224
+ getAvailableChannelByPosition = ()=>{
225
+ let start, end //闭区间
226
+ // if(Settings.bulletSettings.position == BulletPositon.TopHalf){
227
+ // let _topHalfsize = Math.floor(this.positionSize / 2)
228
+ // start = 0
229
+ // end = _topHalfsize - 1
230
+ // }
231
+ // else if(Settings.bulletSettings.position == BulletPositon.BottomHalf){
232
+ // let _topHalfsize = Math.floor(this.positionSize / 2)
233
+ // start = _topHalfsize
234
+ // end = this.positionSize - 1
235
+ // }
236
+ // else{ //Settings.bulletSettings.position == BulletPositon.Full
237
+ start = 0
238
+ end = this.positionSize - 1
239
+ // }
240
+
241
+ for(let index = start; index <= end; index++){
242
+ if(this.hasPosition[index]){
243
+ return index;
244
+ }
245
+ }
246
+
247
+ return -1
248
+ }
249
+
250
+ onItemFree = ()=>{
251
+ bulletDataList.shift();
252
+ }
253
+
254
+ onChannelFree = (channel)=>{
255
+ this.hasPosition[channel] = true;
256
+ }
257
+
258
+ render(){
259
+ let container : CSSProperties = {
260
+ width : this.props.screenWidth + "px",
261
+ height : this.props.screenHeight + "px",
262
+ position : 'absolute',
263
+ overflow : 'hidden',
264
+ // backgroundColor: '#00FFFF66'
265
+ }
266
+
267
+ let screenData = this.props.screenData;
268
+ let commonInfo = new BulletConfig(this.props.screenWidth, screenData.channelHeight, screenData.totalTime);
269
+
270
+ return(
271
+ <div style={container}>
272
+ {bulletDataList.map((value, index)=>{
273
+ return (<BulletItemAnimation key={value.key} bulletInfo={value} bulletConfig={commonInfo}
274
+ onItemFree = {this.onItemFree} onChannelFree = {this.onChannelFree}/>);
275
+ })}
276
+ </div>);
277
+ }
278
+ }
@@ -0,0 +1,17 @@
1
+ .bullet_animation{
2
+ animation-name: barrage;
3
+ animation-duration: 10s;
4
+ animation-timing-function: linear;
5
+ animation-iteration-count: 1
6
+ // background-color: aqua;
7
+ }
8
+
9
+ @keyframes barrage{
10
+ from{
11
+ left: 1334px
12
+ }
13
+
14
+ to{
15
+ left: -400px;
16
+ }
17
+ }
@@ -0,0 +1,115 @@
1
+ import { Component, CSSProperties, JSX } from "preact"
2
+ import { DropdownOptionUI } from "./DropdownOptionUI"
3
+ import { DropdownSpreadMainUI } from "./DropdownSpreadMainUI"
4
+ import { DropdownUnspreadMainUI } from "./DropdownUnspreadMainUI"
5
+
6
+ export interface DropdownConfig<T>{
7
+ spreadStyle: CSSProperties
8
+ datas: T[],
9
+ }
10
+
11
+ export class Dropdown<
12
+ T,
13
+ DDUnspreadMainUI extends DropdownUnspreadMainUI<T>,
14
+ DDSpreadMainUI extends DropdownSpreadMainUI<T>,
15
+ DDOptionUI extends DropdownOptionUI<T>>
16
+ extends Component<
17
+ {
18
+ config: DropdownConfig<T>,
19
+ onChoose: Function,
20
+ defaultIndex: number | null,
21
+ unspreadMainUI: DDUnspreadMainUI,
22
+ spreadMainUI: DDSpreadMainUI,
23
+ optionsUI: DDOptionUI[]
24
+ },
25
+ {
26
+ selectedIndex: number,
27
+ isSpread: boolean // dropdown 列表是否展开
28
+ }>{
29
+
30
+ constructor(props){
31
+ super(props)
32
+
33
+ this.addNetEvents()
34
+ this.addLogicEvents()
35
+
36
+ let initIndex: number = this.props.defaultIndex == null ? 0 : this.props.defaultIndex
37
+
38
+ this.state = {
39
+ selectedIndex: initIndex,
40
+ isSpread: false
41
+ }
42
+ }
43
+
44
+ componentWillUnmount(){
45
+ this.removeLogicEvents()
46
+ this.removeNetEvents()
47
+ }
48
+
49
+ addNetEvents = ()=>{
50
+
51
+ }
52
+
53
+ removeNetEvents = ()=>{
54
+
55
+ }
56
+
57
+ addLogicEvents = ()=>{
58
+
59
+ }
60
+
61
+ removeLogicEvents = ()=>{
62
+
63
+ }
64
+
65
+ openList = ()=>{
66
+ // console.warn("open dropdown====")
67
+ this.setState({
68
+ isSpread: true
69
+ })
70
+ }
71
+
72
+ closeList = ()=>{
73
+ // console.warn("close dropdown====")
74
+ this.setState({
75
+ isSpread: false
76
+ })
77
+ }
78
+
79
+ onChoose = (index: number)=>{
80
+ this.props.onChoose(index)
81
+ // console.warn('dropdown-=----', index)
82
+ this.setState({
83
+ selectedIndex: index,
84
+ isSpread: false
85
+ })
86
+ }
87
+
88
+ render(){
89
+ if(!this.state.isSpread){
90
+ this.props.unspreadMainUI.props.info = this.props.config.datas[this.state.selectedIndex]
91
+ this.props.unspreadMainUI.props.openList = this.openList
92
+
93
+ return (
94
+ <div>
95
+ {this.props.unspreadMainUI}
96
+ </div>)
97
+ }
98
+
99
+ this.props.spreadMainUI.props.info = this.props.config.datas[this.state.selectedIndex]
100
+ this.props.spreadMainUI.props.closeList = this.closeList
101
+
102
+ this.props.optionsUI.forEach((v, index)=>{v.props.onChoose = ()=>{this.onChoose(index)} })
103
+ let _optionsUI = this.props.optionsUI.filter(v => v.props.index != this.state.selectedIndex)
104
+ if(_optionsUI.length > 0) _optionsUI[_optionsUI.length - 1].props["isLast"] = true
105
+
106
+ return (
107
+ <div>
108
+ <div style={this.props.config.spreadStyle}>
109
+ {this.props.spreadMainUI}
110
+ {_optionsUI}
111
+ </div>
112
+ </div>
113
+ )
114
+ }
115
+ }
@@ -0,0 +1,13 @@
1
+ import { Component, JSX } from "preact"
2
+
3
+ /**
4
+ * dropdown 打开时options列表的单个Item UI
5
+ */
6
+ export abstract class DropdownOptionUI<T> extends Component<
7
+ {
8
+ info: T,
9
+ onChoose: Function,
10
+ index: number // 数据下标
11
+ }, any> {
12
+
13
+ }
@@ -0,0 +1,11 @@
1
+ import { Component, JSX } from "preact"
2
+
3
+ /**
4
+ * dropdown 打开时选中框的UI
5
+ */
6
+ export abstract class DropdownSpreadMainUI<T> extends Component<
7
+ {
8
+ info: T,
9
+ closeList: Function
10
+ }, any> {
11
+ }
@@ -0,0 +1,11 @@
1
+ import { Component, JSX } from "preact"
2
+
3
+ /**
4
+ * dropdown 未打开时选中框的UI
5
+ */
6
+ export abstract class DropdownUnspreadMainUI<T> extends Component<
7
+ {
8
+ info: T,
9
+ openList: Function
10
+ }, any> {
11
+ }