@sheinoutmobile/shineoutmobile 1.8.2
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.
Potentially problematic release.
This version of @sheinoutmobile/shineoutmobile might be problematic. Click here for more details.
- package/.eslintignore +20 -0
- package/.eslintrc +8 -0
- package/.gitlab-ci.yml +53 -0
- package/.yarnrc +1 -0
- package/CHANGELOG.md +8 -0
- package/README.md +14 -0
- package/build.config.js +6 -0
- package/doc.config.js +16 -0
- package/lib/index.esm.js +5414 -0
- package/lib/index.esm.js.map +1 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/package.json +47 -0
- package/src/component/button/button.jsx +83 -0
- package/src/component/button/index.jsx +3 -0
- package/src/component/button/style.less +132 -0
- package/src/component/cell/cell.jsx +71 -0
- package/src/component/cell/index.jsx +3 -0
- package/src/component/cell/style.less +86 -0
- package/src/component/cell-group/cell-group.jsx +26 -0
- package/src/component/cell-group/index.jsx +3 -0
- package/src/component/cell-group/style.less +22 -0
- package/src/component/checkbox/checkbox.jsx +92 -0
- package/src/component/checkbox/index.js +3 -0
- package/src/component/checkbox/kind/checkbox-button.jsx +41 -0
- package/src/component/checkbox/style.less +49 -0
- package/src/component/dialog/dialog.jsx +58 -0
- package/src/component/dialog/index.js +3 -0
- package/src/component/dialog/kind/dialog-alert.jsx +22 -0
- package/src/component/dialog/kind/dialog-confirm.jsx +54 -0
- package/src/component/dialog/style.less +80 -0
- package/src/component/drawer/drawer.jsx +151 -0
- package/src/component/drawer/index.jsx +3 -0
- package/src/component/drawer/js/tools.js +1 -0
- package/src/component/drawer/style.less +17 -0
- package/src/component/field/field.jsx +49 -0
- package/src/component/field/index.js +3 -0
- package/src/component/icon/icon.jsx +55 -0
- package/src/component/icon/index.jsx +19 -0
- package/src/component/icon/style.less +9 -0
- package/src/component/icons/index.js +3 -0
- package/src/component/icons/mrp.js +3 -0
- package/src/component/image-previewer/image-previewer.jsx +54 -0
- package/src/component/image-previewer/index.js +3 -0
- package/src/component/index-sort-list/group.jsx +49 -0
- package/src/component/index-sort-list/index-bar.jsx +34 -0
- package/src/component/index-sort-list/index.js +3 -0
- package/src/component/index-sort-list/js/rules.js +14 -0
- package/src/component/index-sort-list/js/sort-rule.js +41 -0
- package/src/component/index-sort-list/list.jsx +110 -0
- package/src/component/index-sort-list/style.less +109 -0
- package/src/component/input/index.js +3 -0
- package/src/component/input/input.jsx +285 -0
- package/src/component/input/style.less +77 -0
- package/src/component/list-view/index.js +3 -0
- package/src/component/list-view/jsx/empty.jsx +23 -0
- package/src/component/list-view/list-view.jsx +165 -0
- package/src/component/list-view/style.less +79 -0
- package/src/component/loading/index.js +3 -0
- package/src/component/loading/loading.jsx +97 -0
- package/src/component/loading/styles.less +128 -0
- package/src/component/multiple-selector/index.jsx +3 -0
- package/src/component/multiple-selector/item.jsx +23 -0
- package/src/component/multiple-selector/multiple-selector.jsx +116 -0
- package/src/component/multiple-selector/selector.jsx +41 -0
- package/src/component/multiple-selector/style.less +78 -0
- package/src/component/notice-bar/index.jsx +3 -0
- package/src/component/notice-bar/notice-bar.jsx +86 -0
- package/src/component/notice-bar/style.less +72 -0
- package/src/component/notify/index.js +37 -0
- package/src/component/notify/notify.jsx +125 -0
- package/src/component/notify/style.less +48 -0
- package/src/component/picker/drawPicker.jsx +110 -0
- package/src/component/picker/index.js +3 -0
- package/src/component/picker/picker.jsx +380 -0
- package/src/component/picker/pickerItem.jsx +31 -0
- package/src/component/picker/style.less +80 -0
- package/src/component/pull-refresh/index.js +3 -0
- package/src/component/pull-refresh/pull-refresh.jsx +46 -0
- package/src/component/search-bar/index.jsx +3 -0
- package/src/component/search-bar/search-bar.jsx +97 -0
- package/src/component/search-bar/style.less +52 -0
- package/src/component/sign/index.jsx +3 -0
- package/src/component/sign/sign.jsx +33 -0
- package/src/component/sign/style.less +56 -0
- package/src/component/sort-item/index.jsx +3 -0
- package/src/component/sort-item/sort-item.jsx +52 -0
- package/src/component/sort-item/style.less +52 -0
- package/src/component/subscript/index.js +3 -0
- package/src/component/subscript/style.less +63 -0
- package/src/component/subscript/subscript.jsx +77 -0
- package/src/component/tab/index.jsx +6 -0
- package/src/component/tab/nav-child.jsx +63 -0
- package/src/component/tab/panel.jsx +22 -0
- package/src/component/tab/style.less +87 -0
- package/src/component/tab/tab.jsx +195 -0
- package/src/component/tag/index.jsx +3 -0
- package/src/component/tag/style.less +56 -0
- package/src/component/tag/tag.jsx +52 -0
- package/src/component/toast/content.jsx +31 -0
- package/src/component/toast/index.js +3 -0
- package/src/component/toast/style.less +50 -0
- package/src/component/toast/toast.jsx +62 -0
- package/src/component/touchable/index.js +3 -0
- package/src/component/touchable/style.less +33 -0
- package/src/component/touchable/touchable.jsx +43 -0
- package/src/component/uploader/index.jsx +445 -0
- package/src/component/uploader/js/get-image-base64.js +31 -0
- package/src/component/uploader/js/get-image-detail.js +26 -0
- package/src/component/uploader/js/index.js +77 -0
- package/src/component/uploader/js/merge-class-name.js +14 -0
- package/src/component/uploader/js/old-compress-function.js +64 -0
- package/src/component/uploader/js/request.js +62 -0
- package/src/component/uploader/js/tools.js +115 -0
- package/src/component/uploader/jsx/config.jsx +36 -0
- package/src/component/uploader/jsx/img-preview.jsx +41 -0
- package/src/component/uploader/jsx/thumbnails.jsx +27 -0
- package/src/component/uploader/styles/index.less +158 -0
- package/src/index.js +1 -0
- package/src/index.jsx +64 -0
- package/src/styles/color.less +51 -0
- package/src/styles/font.less +14 -0
- package/src/styles/format-theme.less +27 -0
- package/src/styles/index.less +26 -0
- package/src/styles/spacing.less +3 -0
- package/src/styles/var.less +3 -0
- package/src/tools/create-body-container.js +47 -0
- package/src/tools/limit-body-scroll.js +17 -0
- package/src/tools/limit-document-scroll.js +12 -0
- package/src/tools/merge-class-name.js +14 -0
- package/src/tools/object-key-check.js +3 -0
- package/src/tools/pinyin.js +6 -0
- package/src/tools/proptypes.js +51 -0
- package/src/tools/style.less +14 -0
- package/test/cases/case-button01.assert.js +6 -0
- package/test/cases/case-button01.source.jsx +28 -0
- package/test/cases/case-checkbox01.assert.js +6 -0
- package/test/cases/case-checkbox01.source.jsx +20 -0
- package/test/cases/case-dialog01.assert.js +6 -0
- package/test/cases/case-dialog01.source.jsx +45 -0
- package/test/cases/case-drawer01.assert.js +6 -0
- package/test/cases/case-drawer01.source.jsx +85 -0
- package/test/cases/case-icons01.assert.js +6 -0
- package/test/cases/case-icons01.source.jsx +25 -0
- package/test/cases/case-indexSortList01.assert.js +6 -0
- package/test/cases/case-indexSortList01.source.jsx +74 -0
- package/test/cases/case-input01.assert.js +6 -0
- package/test/cases/case-input01.source.jsx +24 -0
- package/test/cases/case-listView01.assert.js +6 -0
- package/test/cases/case-listView01.source.jsx +64 -0
- package/test/cases/case-multiplePicker01.assert.js +6 -0
- package/test/cases/case-multiplePicker01.source.jsx +60 -0
- package/test/cases/case-multipleSelector01.assert.js +6 -0
- package/test/cases/case-multipleSelector01.source.jsx +49 -0
- package/test/cases/case-noticebar01.assert.js +6 -0
- package/test/cases/case-noticebar01.source.jsx +21 -0
- package/test/cases/case-picker01.assert.js +6 -0
- package/test/cases/case-picker01.source.jsx +61 -0
- package/test/cases/case-refresh01.assert.js +6 -0
- package/test/cases/case-refresh01.source.jsx +33 -0
- package/test/cases/case-sign01.assert.js +6 -0
- package/test/cases/case-sign01.source.jsx +21 -0
- package/test/cases/case-subscript01.assert.js +6 -0
- package/test/cases/case-subscript01.source.jsx +30 -0
- package/test/cases/case-tab01.assert.js +6 -0
- package/test/cases/case-tab01.source.jsx +51 -0
- package/test/cases/case-toast01.assert.js +6 -0
- package/test/cases/case-toast01.source.jsx +32 -0
- package/test/cases/case-uploader01.assert.js +6 -0
- package/test/cases/case-uploader01.source.jsx +45 -0
- package/test.config.js +25 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { getProps } from '../../tools/proptypes';
|
|
4
|
+
import { prohibited, restore } from '../../tools/limit-document-scroll';
|
|
5
|
+
import mergeClassName from '../../tools/merge-class-name';
|
|
6
|
+
import styles from './style.less';
|
|
7
|
+
|
|
8
|
+
import Empty from './jsx/empty';
|
|
9
|
+
|
|
10
|
+
const maxTranslateY = 80;
|
|
11
|
+
|
|
12
|
+
class ListView extends React.Component {
|
|
13
|
+
constructor(props) {
|
|
14
|
+
super(props);
|
|
15
|
+
this.state = {
|
|
16
|
+
translateY: 0, // 下拉时,滚动容器偏移距离(竖直方向)。只在滚动到顶部(或者说是没滚动过)的时候,才会触发事件动态改变便宜距离
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
this.startY = 0; // 手机触碰事件中手指在滚动容器的初始位置(竖直方向)
|
|
20
|
+
this.scrollTop = 0; // 滚动时距离顶部的距离
|
|
21
|
+
this.scrolling = false; // 判断容器是否处于滚动,用于给「下拉刷新」增加判断条件
|
|
22
|
+
this.timeout = null;
|
|
23
|
+
|
|
24
|
+
this.onScroll = this.onScroll.bind(this);
|
|
25
|
+
this.onTouchStart = this.onTouchStart.bind(this);
|
|
26
|
+
this.onTouchMove = this.onTouchMove.bind(this);
|
|
27
|
+
this.onTouchEnd = this.onTouchEnd.bind(this);
|
|
28
|
+
|
|
29
|
+
this.container = React.createRef();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
componentDidMount() {
|
|
33
|
+
this.container.current.addEventListener(
|
|
34
|
+
'touchmove',
|
|
35
|
+
e => (
|
|
36
|
+
!this.scrollTop
|
|
37
|
+
&& e.touches[0].pageY > this.startY
|
|
38
|
+
&& e.cancelable
|
|
39
|
+
&& e.preventDefault()),
|
|
40
|
+
{ passive: false },
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 监听滚动事件,为了判断何时「触底」
|
|
45
|
+
onScroll(e) {
|
|
46
|
+
// 设定滚动延迟是因为Android手机touchmove事件会影响touchend的触发,但是设定e.preventDefault会在滚动时
|
|
47
|
+
this.scrolling = true;
|
|
48
|
+
if (this.timeout) clearTimeout(this.timeout);
|
|
49
|
+
this.timeout = setTimeout(() => {
|
|
50
|
+
this.scrolling = false;
|
|
51
|
+
}, 100);
|
|
52
|
+
|
|
53
|
+
const { onTouchBottom } = this.props;
|
|
54
|
+
const { scrollHeight, clientHeight, scrollTop } = e.target;
|
|
55
|
+
if (scrollHeight - clientHeight - scrollTop === 0 && typeof onTouchBottom === 'function') onTouchBottom();
|
|
56
|
+
this.scrollTop = scrollTop;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
onTouchStart(e) {
|
|
60
|
+
this.startY = !this.scrollTop ? e.touches[0].pageY : 0;
|
|
61
|
+
prohibited();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 监听触碰滑动事件,目的是在触顶的时候,进行滚动容器的偏移
|
|
65
|
+
onTouchMove(e) {
|
|
66
|
+
const { loading } = this.props;
|
|
67
|
+
if (this.scrolling || loading) return; // 在滚动和loading状态下,不允许下拉刷新
|
|
68
|
+
|
|
69
|
+
const touche = e.touches[0];
|
|
70
|
+
|
|
71
|
+
// 滚到顶部时,记录手指相对于滚动容器的初始位置,为后续的事件判断提供先决条件
|
|
72
|
+
if (!this.scrollTop && !this.startY) this.startY = touche.pageY;
|
|
73
|
+
|
|
74
|
+
if (touche.pageY > this.startY && !this.scrollTop) {
|
|
75
|
+
const translateY = touche.pageY - this.startY > maxTranslateY
|
|
76
|
+
? maxTranslateY
|
|
77
|
+
: touche.pageY - this.startY;
|
|
78
|
+
this.setState({ translateY });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 监听触碰结束事件,目的是判断是否需要触发「下拉刷新」事件
|
|
83
|
+
onTouchEnd() {
|
|
84
|
+
const { onRefresh } = this.props;
|
|
85
|
+
const { translateY } = this.state;
|
|
86
|
+
if (typeof onRefresh === 'function' && translateY > 30) onRefresh();
|
|
87
|
+
this.setState({ translateY: 0 });
|
|
88
|
+
this.startY = 0;
|
|
89
|
+
restore();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
scrollToTop = () => {
|
|
93
|
+
if (this.container) {
|
|
94
|
+
this.container.current.scrollTop = 0;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
render() {
|
|
99
|
+
const {
|
|
100
|
+
loading, loadingContent,
|
|
101
|
+
children, empty, emptyText, emptySize, refreshContent,
|
|
102
|
+
className, ...other
|
|
103
|
+
} = this.props;
|
|
104
|
+
const { translateY } = this.state;
|
|
105
|
+
return (
|
|
106
|
+
<div className={styles.body}>
|
|
107
|
+
<div
|
|
108
|
+
onScroll={this.onScroll}
|
|
109
|
+
onTouchStart={this.onTouchStart}
|
|
110
|
+
onTouchMove={this.onTouchMove}
|
|
111
|
+
onTouchEnd={this.onTouchEnd}
|
|
112
|
+
className={mergeClassName([styles.container, loading && styles.noScroll, className])}
|
|
113
|
+
{...other}
|
|
114
|
+
style={{ transform: `translateY(${translateY}px)` }}
|
|
115
|
+
ref={this.container}
|
|
116
|
+
>
|
|
117
|
+
{
|
|
118
|
+
React.Children.count(children) === 0 && !loading
|
|
119
|
+
? empty || <Empty text={emptyText} size={emptySize} />
|
|
120
|
+
: children
|
|
121
|
+
}
|
|
122
|
+
{
|
|
123
|
+
loading && (
|
|
124
|
+
<div
|
|
125
|
+
style={{ top: this.scrollTop }}
|
|
126
|
+
className={styles.loading}
|
|
127
|
+
>
|
|
128
|
+
{loadingContent}
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
</div>
|
|
133
|
+
{
|
|
134
|
+
translateY > 0
|
|
135
|
+
&& (
|
|
136
|
+
<div style={{ height: translateY }} className={styles.refreshContainer}>
|
|
137
|
+
{refreshContent}
|
|
138
|
+
</div>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
ListView.propTypes = {
|
|
147
|
+
...getProps(PropTypes, 'className', 'children'),
|
|
148
|
+
empty: PropTypes.node,
|
|
149
|
+
emptyText: PropTypes.node,
|
|
150
|
+
emptySize: PropTypes.oneOf(['small', 'default', 'large']),
|
|
151
|
+
loading: PropTypes.bool,
|
|
152
|
+
loadingContent: PropTypes.node,
|
|
153
|
+
refreshContent: PropTypes.node,
|
|
154
|
+
onTouchBottom: PropTypes.func, // 触底事件
|
|
155
|
+
onRefresh: PropTypes.func, // 下拉刷新事件
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
ListView.defaultProps = {
|
|
159
|
+
emptyText: '暂无数据',
|
|
160
|
+
emptySize: 'default',
|
|
161
|
+
loadingContent: '加载中...',
|
|
162
|
+
refreshContent: '松手刷新',
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export default ListView;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
@import "../../styles/color";
|
|
2
|
+
|
|
3
|
+
.container{
|
|
4
|
+
height: 100%;
|
|
5
|
+
overflow: auto;
|
|
6
|
+
-webkit-overflow-scrolling: touch;
|
|
7
|
+
|
|
8
|
+
position: relative;
|
|
9
|
+
|
|
10
|
+
//background: @white;
|
|
11
|
+
|
|
12
|
+
.loading{
|
|
13
|
+
width: 100%;
|
|
14
|
+
height: 100%;
|
|
15
|
+
|
|
16
|
+
display: flex;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
align-items: center;
|
|
19
|
+
|
|
20
|
+
position: absolute;
|
|
21
|
+
top: 0;
|
|
22
|
+
|
|
23
|
+
color: @white;
|
|
24
|
+
background: rgba(0, 0, 0, 0.1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.noScroll{
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.body{
|
|
33
|
+
height: 100%;
|
|
34
|
+
position: relative;
|
|
35
|
+
|
|
36
|
+
//background: @background-color;
|
|
37
|
+
|
|
38
|
+
.refreshContainer{
|
|
39
|
+
width: 100%;
|
|
40
|
+
display: flex;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
align-items: center;
|
|
43
|
+
|
|
44
|
+
position: absolute;
|
|
45
|
+
top: 0;
|
|
46
|
+
|
|
47
|
+
color: @gray-darker;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.empty{
|
|
51
|
+
height: 100%;
|
|
52
|
+
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
|
|
58
|
+
&-icon{
|
|
59
|
+
margin-bottom: 10px;
|
|
60
|
+
color: @blue-gray;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&-size-small{
|
|
64
|
+
font-size: 86px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&-size-default{
|
|
68
|
+
font-size: 106px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&-size-large{
|
|
72
|
+
font-size: 126px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
text{
|
|
76
|
+
color: @gray-darker;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styles from './styles.less'
|
|
4
|
+
import mergeClassName from '../../tools/merge-class-name';
|
|
5
|
+
|
|
6
|
+
class Loading extends React.PureComponent {
|
|
7
|
+
renderIcon() {
|
|
8
|
+
const { type } = this.props;
|
|
9
|
+
if (type === 'spinner') {
|
|
10
|
+
const Spin = [];
|
|
11
|
+
for (let i = 0; i < 12; i++) {
|
|
12
|
+
Spin.push(<i key={i} />);
|
|
13
|
+
}
|
|
14
|
+
return Spin;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<svg className={styles['loading__circular']} viewBox="25 25 50 50">
|
|
19
|
+
<circle cx="50" cy="50" r="20" fill="none" />
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
renderText() {
|
|
24
|
+
const { textSize, children } = this.props;
|
|
25
|
+
if (children) {
|
|
26
|
+
const style = textSize !== undefined ? {
|
|
27
|
+
fontSize: parseInt(textSize, 10)
|
|
28
|
+
} : {};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<span className={styles['loading__text']} style={style}>
|
|
32
|
+
{children}
|
|
33
|
+
</span>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
render() {
|
|
39
|
+
const { color, size, type, vertical, className } = this.props;
|
|
40
|
+
|
|
41
|
+
const style = { color };
|
|
42
|
+
if (size) {
|
|
43
|
+
const iconSize = parseInt(size, 10);
|
|
44
|
+
style.width = iconSize;
|
|
45
|
+
style.height = iconSize;
|
|
46
|
+
}
|
|
47
|
+
const icon = this.renderIcon();
|
|
48
|
+
const text = this.renderText();
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
style={this.props.style}
|
|
53
|
+
className={
|
|
54
|
+
mergeClassName([
|
|
55
|
+
// van-loading van-loading--circular
|
|
56
|
+
// van-loading van-loading--spinner van-loading--vertical
|
|
57
|
+
styles['loading'],
|
|
58
|
+
styles[`loading__${type}`],
|
|
59
|
+
(vertical ? styles[`loading--vertical`] : ''),
|
|
60
|
+
className
|
|
61
|
+
])
|
|
62
|
+
}
|
|
63
|
+
>
|
|
64
|
+
<span
|
|
65
|
+
className={
|
|
66
|
+
// van-loading__spinner van-loading__spinner--circular
|
|
67
|
+
// van-loading__spinner van-loading__spinner--spinner
|
|
68
|
+
mergeClassName([
|
|
69
|
+
styles[`loading__spinner`],
|
|
70
|
+
styles[`loading__spinner--${type}`],
|
|
71
|
+
])
|
|
72
|
+
}
|
|
73
|
+
style={style}
|
|
74
|
+
>
|
|
75
|
+
{icon}
|
|
76
|
+
</span>
|
|
77
|
+
{text}
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Loading.propTypes = {
|
|
84
|
+
style: PropTypes.object,
|
|
85
|
+
className: PropTypes.string,
|
|
86
|
+
color: PropTypes.string,
|
|
87
|
+
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
88
|
+
vertical: PropTypes.bool,
|
|
89
|
+
textSize: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
90
|
+
type: PropTypes.oneOf(['circular', 'spinner']),
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
Loading.defaultProps = {
|
|
94
|
+
type: 'circular'
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export default Loading;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
@gray-5: #c8c9cc;
|
|
2
|
+
@gray-6: #969799;
|
|
3
|
+
@font-size-md: 14px;
|
|
4
|
+
|
|
5
|
+
@padding-base: 4px;
|
|
6
|
+
@padding-xs: @padding-base * 2;
|
|
7
|
+
@padding-sm: @padding-base * 3;
|
|
8
|
+
@padding-md: @padding-base * 4;
|
|
9
|
+
@padding-lg: @padding-base * 6;
|
|
10
|
+
@padding-xl: @padding-base * 8;
|
|
11
|
+
|
|
12
|
+
@loading-text-color: @gray-6;
|
|
13
|
+
@loading-text-font-size: @font-size-md;
|
|
14
|
+
@loading-spinner-color: @gray-5;
|
|
15
|
+
@loading-spinner-size: 30px;
|
|
16
|
+
@loading-spinner-animation-duration: 1s;
|
|
17
|
+
|
|
18
|
+
@keyframes van-rotate {
|
|
19
|
+
from {
|
|
20
|
+
transform: rotate(0deg);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
to {
|
|
24
|
+
transform: rotate(360deg);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.loading {
|
|
29
|
+
position: relative;
|
|
30
|
+
color: @loading-spinner-color;
|
|
31
|
+
font-size: 0;
|
|
32
|
+
vertical-align: middle;
|
|
33
|
+
|
|
34
|
+
&__spinner {
|
|
35
|
+
position: relative;
|
|
36
|
+
display: inline-block;
|
|
37
|
+
width: @loading-spinner-size;
|
|
38
|
+
// compatible for 1.x, users may set width or height in root element
|
|
39
|
+
max-width: 100%;
|
|
40
|
+
height: @loading-spinner-size;
|
|
41
|
+
max-height: 100%;
|
|
42
|
+
vertical-align: middle;
|
|
43
|
+
animation: van-rotate @loading-spinner-animation-duration linear infinite;
|
|
44
|
+
|
|
45
|
+
&--spinner {
|
|
46
|
+
animation-timing-function: steps(12);
|
|
47
|
+
|
|
48
|
+
i {
|
|
49
|
+
position: absolute;
|
|
50
|
+
top: 0;
|
|
51
|
+
left: 0;
|
|
52
|
+
width: 100%;
|
|
53
|
+
height: 100%;
|
|
54
|
+
|
|
55
|
+
&::before {
|
|
56
|
+
display: block;
|
|
57
|
+
width: 2px;
|
|
58
|
+
height: 25%;
|
|
59
|
+
margin: 0 auto;
|
|
60
|
+
background-color: currentColor;
|
|
61
|
+
border-radius: 40%;
|
|
62
|
+
content: ' ';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&--circular {
|
|
68
|
+
animation-duration: 2s;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&__circular {
|
|
73
|
+
display: block;
|
|
74
|
+
width: 100%;
|
|
75
|
+
height: 100%;
|
|
76
|
+
|
|
77
|
+
circle {
|
|
78
|
+
animation: van-circular 1.5s ease-in-out infinite;
|
|
79
|
+
stroke: currentColor;
|
|
80
|
+
stroke-width: 3;
|
|
81
|
+
stroke-linecap: round;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&__text {
|
|
86
|
+
display: inline-block;
|
|
87
|
+
margin-left: @padding-xs;
|
|
88
|
+
color: @loading-text-color;
|
|
89
|
+
font-size: @loading-text-font-size;
|
|
90
|
+
vertical-align: middle;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&--vertical {
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
align-items: center;
|
|
97
|
+
|
|
98
|
+
.loading__text {
|
|
99
|
+
margin: @padding-xs 0 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@keyframes van-circular {
|
|
105
|
+
0% {
|
|
106
|
+
stroke-dasharray: 1, 200;
|
|
107
|
+
stroke-dashoffset: 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
50% {
|
|
111
|
+
stroke-dasharray: 90, 150;
|
|
112
|
+
stroke-dashoffset: -40;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
100% {
|
|
116
|
+
stroke-dasharray: 90, 150;
|
|
117
|
+
stroke-dashoffset: -120;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.generate-spinner(@n, @i: 1) when (@i =< @n) {
|
|
122
|
+
.loading__spinner--spinner i:nth-of-type(@{i}) {
|
|
123
|
+
transform: rotate(@i * 30deg);
|
|
124
|
+
opacity: 1 - (0.75 / 12) * (@i - 1);
|
|
125
|
+
}
|
|
126
|
+
.generate-spinner(@n, (@i + 1));
|
|
127
|
+
}
|
|
128
|
+
.generate-spinner(12);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styles from './style.less';
|
|
4
|
+
|
|
5
|
+
const Item = (props) => {
|
|
6
|
+
const { click, label, value } = props;
|
|
7
|
+
return (
|
|
8
|
+
<li
|
|
9
|
+
onClick={() => click(value)}
|
|
10
|
+
className={styles.item}
|
|
11
|
+
>
|
|
12
|
+
{label}
|
|
13
|
+
</li>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
Item.propTypes = {
|
|
18
|
+
click: PropTypes.func,
|
|
19
|
+
label: PropTypes.string,
|
|
20
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default Item;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React, { PureComponent, isValidElement, createRef } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styles from './style.less';
|
|
4
|
+
import Drawer from '../drawer';
|
|
5
|
+
import Selector from './selector';
|
|
6
|
+
import Item from './item';
|
|
7
|
+
|
|
8
|
+
class MultipleSelector extends PureComponent {
|
|
9
|
+
constructor(props) {
|
|
10
|
+
super(props);
|
|
11
|
+
this.state = {
|
|
12
|
+
currentName: undefined,
|
|
13
|
+
currentValue: {},
|
|
14
|
+
};
|
|
15
|
+
this.click = this.click.bind(this);
|
|
16
|
+
this.clickItem = this.clickItem.bind(this);
|
|
17
|
+
this.container = createRef();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
createTitle() {
|
|
21
|
+
const { title } = this.props;
|
|
22
|
+
if (isValidElement(title)) return title;
|
|
23
|
+
return <div className={styles['normal-title']}>{title}</div>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
createContainerStyle() {
|
|
27
|
+
const { currentName } = this.state;
|
|
28
|
+
const style = {};
|
|
29
|
+
if (currentName) {
|
|
30
|
+
const width = this.container.current.clientWidth;
|
|
31
|
+
Object.assign(style, { transform: `translateX(-${width}px)` });
|
|
32
|
+
}
|
|
33
|
+
return style;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
click(name) {
|
|
37
|
+
this.setState({ currentName: name });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
clickItem(val) {
|
|
41
|
+
const { currentName, currentValue } = this.state;
|
|
42
|
+
const { onChange, value = currentValue } = this.props;
|
|
43
|
+
const newValue = Object.assign({}, value, { [currentName]: val });
|
|
44
|
+
this.setState({
|
|
45
|
+
currentName: null,
|
|
46
|
+
currentValue: newValue,
|
|
47
|
+
});
|
|
48
|
+
onChange(newValue);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
render() {
|
|
52
|
+
const { currentName, currentValue } = this.state;
|
|
53
|
+
const {
|
|
54
|
+
visible,
|
|
55
|
+
option, value = currentValue,
|
|
56
|
+
onClose,
|
|
57
|
+
extraComponent,
|
|
58
|
+
} = this.props;
|
|
59
|
+
|
|
60
|
+
const titleEl = this.createTitle();
|
|
61
|
+
|
|
62
|
+
const containerStyle = this.createContainerStyle();
|
|
63
|
+
|
|
64
|
+
const currentOption = option.find(op => op.name === currentName) || { data: [] };
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Drawer
|
|
68
|
+
visible={visible}
|
|
69
|
+
onClose={onClose}
|
|
70
|
+
position="bottom"
|
|
71
|
+
drawerClass={styles.drawer}
|
|
72
|
+
>
|
|
73
|
+
{titleEl}
|
|
74
|
+
<div className={styles.container} style={containerStyle}>
|
|
75
|
+
<ul ref={this.container} className={styles['container-content']}>
|
|
76
|
+
{
|
|
77
|
+
option.map(op => (
|
|
78
|
+
<Selector
|
|
79
|
+
{...op}
|
|
80
|
+
click={this.click}
|
|
81
|
+
selected={op.data.find(d => value[op.name] === d.value)}
|
|
82
|
+
/>
|
|
83
|
+
))
|
|
84
|
+
}
|
|
85
|
+
</ul>
|
|
86
|
+
<ul className={styles['container-content']}>
|
|
87
|
+
{
|
|
88
|
+
currentOption.data.map(da => <Item {...da} click={this.clickItem} />)
|
|
89
|
+
}
|
|
90
|
+
</ul>
|
|
91
|
+
</div>
|
|
92
|
+
{
|
|
93
|
+
!currentName
|
|
94
|
+
? extraComponent
|
|
95
|
+
: null
|
|
96
|
+
}
|
|
97
|
+
</Drawer>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
MultipleSelector.propTypes = {
|
|
103
|
+
visible: PropTypes.bool,
|
|
104
|
+
option: PropTypes.arrayOf(PropTypes.object),
|
|
105
|
+
value: PropTypes.objectOf(PropTypes.any),
|
|
106
|
+
onClose: PropTypes.func,
|
|
107
|
+
onChange: PropTypes.func,
|
|
108
|
+
title: PropTypes.oneOfType([PropTypes.string, PropTypes.symbol]),
|
|
109
|
+
extraComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.symbol]),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
MultipleSelector.defaultProps = {
|
|
113
|
+
option: [],
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export default MultipleSelector;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { PureComponent } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styles from './style.less';
|
|
4
|
+
|
|
5
|
+
import Icon from '../icons';
|
|
6
|
+
|
|
7
|
+
class Selector extends PureComponent {
|
|
8
|
+
render() {
|
|
9
|
+
const { name, label, data, selected, click } = this.props;
|
|
10
|
+
const next = data && data.length > 0;
|
|
11
|
+
return (
|
|
12
|
+
<li
|
|
13
|
+
className={styles.selector}
|
|
14
|
+
onClick={() => next && click(name)}
|
|
15
|
+
>
|
|
16
|
+
<span>{label}</span>
|
|
17
|
+
<span>
|
|
18
|
+
<span className={styles['selector-result-text']}>{selected.label}</span>
|
|
19
|
+
{
|
|
20
|
+
next
|
|
21
|
+
? <Icon className={styles['selector-right-icon']} name="Forward" />
|
|
22
|
+
: null
|
|
23
|
+
}
|
|
24
|
+
</span>
|
|
25
|
+
</li>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Selector.propTypes = {
|
|
31
|
+
click: PropTypes.func,
|
|
32
|
+
label: PropTypes.string,
|
|
33
|
+
name: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]),
|
|
34
|
+
selected: PropTypes.objectOf(PropTypes.any),
|
|
35
|
+
data: PropTypes.arrayOf(PropTypes.object),
|
|
36
|
+
};
|
|
37
|
+
Selector.defaultProps = {
|
|
38
|
+
selected: {},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default Selector;
|