@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.

Files changed (171) hide show
  1. package/.eslintignore +20 -0
  2. package/.eslintrc +8 -0
  3. package/.gitlab-ci.yml +53 -0
  4. package/.yarnrc +1 -0
  5. package/CHANGELOG.md +8 -0
  6. package/README.md +14 -0
  7. package/build.config.js +6 -0
  8. package/doc.config.js +16 -0
  9. package/lib/index.esm.js +5414 -0
  10. package/lib/index.esm.js.map +1 -0
  11. package/lib/index.js +8 -0
  12. package/lib/index.js.map +1 -0
  13. package/package.json +47 -0
  14. package/src/component/button/button.jsx +83 -0
  15. package/src/component/button/index.jsx +3 -0
  16. package/src/component/button/style.less +132 -0
  17. package/src/component/cell/cell.jsx +71 -0
  18. package/src/component/cell/index.jsx +3 -0
  19. package/src/component/cell/style.less +86 -0
  20. package/src/component/cell-group/cell-group.jsx +26 -0
  21. package/src/component/cell-group/index.jsx +3 -0
  22. package/src/component/cell-group/style.less +22 -0
  23. package/src/component/checkbox/checkbox.jsx +92 -0
  24. package/src/component/checkbox/index.js +3 -0
  25. package/src/component/checkbox/kind/checkbox-button.jsx +41 -0
  26. package/src/component/checkbox/style.less +49 -0
  27. package/src/component/dialog/dialog.jsx +58 -0
  28. package/src/component/dialog/index.js +3 -0
  29. package/src/component/dialog/kind/dialog-alert.jsx +22 -0
  30. package/src/component/dialog/kind/dialog-confirm.jsx +54 -0
  31. package/src/component/dialog/style.less +80 -0
  32. package/src/component/drawer/drawer.jsx +151 -0
  33. package/src/component/drawer/index.jsx +3 -0
  34. package/src/component/drawer/js/tools.js +1 -0
  35. package/src/component/drawer/style.less +17 -0
  36. package/src/component/field/field.jsx +49 -0
  37. package/src/component/field/index.js +3 -0
  38. package/src/component/icon/icon.jsx +55 -0
  39. package/src/component/icon/index.jsx +19 -0
  40. package/src/component/icon/style.less +9 -0
  41. package/src/component/icons/index.js +3 -0
  42. package/src/component/icons/mrp.js +3 -0
  43. package/src/component/image-previewer/image-previewer.jsx +54 -0
  44. package/src/component/image-previewer/index.js +3 -0
  45. package/src/component/index-sort-list/group.jsx +49 -0
  46. package/src/component/index-sort-list/index-bar.jsx +34 -0
  47. package/src/component/index-sort-list/index.js +3 -0
  48. package/src/component/index-sort-list/js/rules.js +14 -0
  49. package/src/component/index-sort-list/js/sort-rule.js +41 -0
  50. package/src/component/index-sort-list/list.jsx +110 -0
  51. package/src/component/index-sort-list/style.less +109 -0
  52. package/src/component/input/index.js +3 -0
  53. package/src/component/input/input.jsx +285 -0
  54. package/src/component/input/style.less +77 -0
  55. package/src/component/list-view/index.js +3 -0
  56. package/src/component/list-view/jsx/empty.jsx +23 -0
  57. package/src/component/list-view/list-view.jsx +165 -0
  58. package/src/component/list-view/style.less +79 -0
  59. package/src/component/loading/index.js +3 -0
  60. package/src/component/loading/loading.jsx +97 -0
  61. package/src/component/loading/styles.less +128 -0
  62. package/src/component/multiple-selector/index.jsx +3 -0
  63. package/src/component/multiple-selector/item.jsx +23 -0
  64. package/src/component/multiple-selector/multiple-selector.jsx +116 -0
  65. package/src/component/multiple-selector/selector.jsx +41 -0
  66. package/src/component/multiple-selector/style.less +78 -0
  67. package/src/component/notice-bar/index.jsx +3 -0
  68. package/src/component/notice-bar/notice-bar.jsx +86 -0
  69. package/src/component/notice-bar/style.less +72 -0
  70. package/src/component/notify/index.js +37 -0
  71. package/src/component/notify/notify.jsx +125 -0
  72. package/src/component/notify/style.less +48 -0
  73. package/src/component/picker/drawPicker.jsx +110 -0
  74. package/src/component/picker/index.js +3 -0
  75. package/src/component/picker/picker.jsx +380 -0
  76. package/src/component/picker/pickerItem.jsx +31 -0
  77. package/src/component/picker/style.less +80 -0
  78. package/src/component/pull-refresh/index.js +3 -0
  79. package/src/component/pull-refresh/pull-refresh.jsx +46 -0
  80. package/src/component/search-bar/index.jsx +3 -0
  81. package/src/component/search-bar/search-bar.jsx +97 -0
  82. package/src/component/search-bar/style.less +52 -0
  83. package/src/component/sign/index.jsx +3 -0
  84. package/src/component/sign/sign.jsx +33 -0
  85. package/src/component/sign/style.less +56 -0
  86. package/src/component/sort-item/index.jsx +3 -0
  87. package/src/component/sort-item/sort-item.jsx +52 -0
  88. package/src/component/sort-item/style.less +52 -0
  89. package/src/component/subscript/index.js +3 -0
  90. package/src/component/subscript/style.less +63 -0
  91. package/src/component/subscript/subscript.jsx +77 -0
  92. package/src/component/tab/index.jsx +6 -0
  93. package/src/component/tab/nav-child.jsx +63 -0
  94. package/src/component/tab/panel.jsx +22 -0
  95. package/src/component/tab/style.less +87 -0
  96. package/src/component/tab/tab.jsx +195 -0
  97. package/src/component/tag/index.jsx +3 -0
  98. package/src/component/tag/style.less +56 -0
  99. package/src/component/tag/tag.jsx +52 -0
  100. package/src/component/toast/content.jsx +31 -0
  101. package/src/component/toast/index.js +3 -0
  102. package/src/component/toast/style.less +50 -0
  103. package/src/component/toast/toast.jsx +62 -0
  104. package/src/component/touchable/index.js +3 -0
  105. package/src/component/touchable/style.less +33 -0
  106. package/src/component/touchable/touchable.jsx +43 -0
  107. package/src/component/uploader/index.jsx +445 -0
  108. package/src/component/uploader/js/get-image-base64.js +31 -0
  109. package/src/component/uploader/js/get-image-detail.js +26 -0
  110. package/src/component/uploader/js/index.js +77 -0
  111. package/src/component/uploader/js/merge-class-name.js +14 -0
  112. package/src/component/uploader/js/old-compress-function.js +64 -0
  113. package/src/component/uploader/js/request.js +62 -0
  114. package/src/component/uploader/js/tools.js +115 -0
  115. package/src/component/uploader/jsx/config.jsx +36 -0
  116. package/src/component/uploader/jsx/img-preview.jsx +41 -0
  117. package/src/component/uploader/jsx/thumbnails.jsx +27 -0
  118. package/src/component/uploader/styles/index.less +158 -0
  119. package/src/index.js +1 -0
  120. package/src/index.jsx +64 -0
  121. package/src/styles/color.less +51 -0
  122. package/src/styles/font.less +14 -0
  123. package/src/styles/format-theme.less +27 -0
  124. package/src/styles/index.less +26 -0
  125. package/src/styles/spacing.less +3 -0
  126. package/src/styles/var.less +3 -0
  127. package/src/tools/create-body-container.js +47 -0
  128. package/src/tools/limit-body-scroll.js +17 -0
  129. package/src/tools/limit-document-scroll.js +12 -0
  130. package/src/tools/merge-class-name.js +14 -0
  131. package/src/tools/object-key-check.js +3 -0
  132. package/src/tools/pinyin.js +6 -0
  133. package/src/tools/proptypes.js +51 -0
  134. package/src/tools/style.less +14 -0
  135. package/test/cases/case-button01.assert.js +6 -0
  136. package/test/cases/case-button01.source.jsx +28 -0
  137. package/test/cases/case-checkbox01.assert.js +6 -0
  138. package/test/cases/case-checkbox01.source.jsx +20 -0
  139. package/test/cases/case-dialog01.assert.js +6 -0
  140. package/test/cases/case-dialog01.source.jsx +45 -0
  141. package/test/cases/case-drawer01.assert.js +6 -0
  142. package/test/cases/case-drawer01.source.jsx +85 -0
  143. package/test/cases/case-icons01.assert.js +6 -0
  144. package/test/cases/case-icons01.source.jsx +25 -0
  145. package/test/cases/case-indexSortList01.assert.js +6 -0
  146. package/test/cases/case-indexSortList01.source.jsx +74 -0
  147. package/test/cases/case-input01.assert.js +6 -0
  148. package/test/cases/case-input01.source.jsx +24 -0
  149. package/test/cases/case-listView01.assert.js +6 -0
  150. package/test/cases/case-listView01.source.jsx +64 -0
  151. package/test/cases/case-multiplePicker01.assert.js +6 -0
  152. package/test/cases/case-multiplePicker01.source.jsx +60 -0
  153. package/test/cases/case-multipleSelector01.assert.js +6 -0
  154. package/test/cases/case-multipleSelector01.source.jsx +49 -0
  155. package/test/cases/case-noticebar01.assert.js +6 -0
  156. package/test/cases/case-noticebar01.source.jsx +21 -0
  157. package/test/cases/case-picker01.assert.js +6 -0
  158. package/test/cases/case-picker01.source.jsx +61 -0
  159. package/test/cases/case-refresh01.assert.js +6 -0
  160. package/test/cases/case-refresh01.source.jsx +33 -0
  161. package/test/cases/case-sign01.assert.js +6 -0
  162. package/test/cases/case-sign01.source.jsx +21 -0
  163. package/test/cases/case-subscript01.assert.js +6 -0
  164. package/test/cases/case-subscript01.source.jsx +30 -0
  165. package/test/cases/case-tab01.assert.js +6 -0
  166. package/test/cases/case-tab01.source.jsx +51 -0
  167. package/test/cases/case-toast01.assert.js +6 -0
  168. package/test/cases/case-toast01.source.jsx +32 -0
  169. package/test/cases/case-uploader01.assert.js +6 -0
  170. package/test/cases/case-uploader01.source.jsx +45 -0
  171. 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,3 @@
1
+ import Loading from './loading'
2
+
3
+ export default Loading
@@ -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,3 @@
1
+ import MultipleSelector from './multiple-selector';
2
+
3
+ export default MultipleSelector;
@@ -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;