@cloudbase/weda-ui 0.2.5 → 0.2.8

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 (150) hide show
  1. package/package.json +4 -4
  2. package/src/.DS_Store +0 -0
  3. package/src/configs/components/container.json +2 -1
  4. package/src/configs/components/form/input.json +6 -0
  5. package/src/configs/components/form/richText.json +2 -1
  6. package/src/configs/components/form/uploader.json +10 -5
  7. package/src/configs/components/image.json +2 -1
  8. package/src/configs/components/link.json +2 -1
  9. package/src/configs/components/richtextview.json +2 -1
  10. package/src/configs/components/scrollVeiw.json +2 -1
  11. package/src/configs/components/swiper.json +2 -1
  12. package/src/configs/components/tabs.json +31 -86
  13. package/src/configs/components/text.json +2 -1
  14. package/src/configs/index.js +3 -5
  15. package/src/index.js +2 -3
  16. package/src/mp/components/form/input/index.js +5 -1
  17. package/src/mp/components/form/input/index.wxml +2 -1
  18. package/src/mp/components/form/select/index.js +2 -2
  19. package/src/mp/components/form/textarea/index.wxml +1 -0
  20. package/src/mp/components/form/uploader/index.js +50 -13
  21. package/src/mp/components/form/uploader/index.wxml +11 -1
  22. package/src/mp/components/image/index.js +57 -8
  23. package/src/mp/components/image/index.json +4 -1
  24. package/src/mp/components/image/index.wxml +4 -2
  25. package/src/mp/components/image/index.wxss +15 -0
  26. package/src/mp/components/richText/index.wxml +3 -1
  27. package/src/mp/components/tabs/index.js +22 -6
  28. package/src/mp/utils/deepEqual.js +42 -0
  29. package/src/web/actions/index.js +2 -4
  30. package/src/web/components/form/checkbox/index.jsx +8 -10
  31. package/src/web/components/form/formcell/index.jsx +1 -1
  32. package/src/web/components/form/input/index.jsx +16 -18
  33. package/src/web/components/form/radio/index.jsx +7 -7
  34. package/src/web/components/form/select/h5.jsx +1 -1
  35. package/src/web/components/form/select/region/{cities.json → cities.js} +2 -2
  36. package/src/web/components/form/select/region/index.js +3 -3
  37. package/src/web/components/form/select/region/{provinces.json → provinces.js} +2 -2
  38. package/src/web/components/form/select/region/{regions.json → regions.js} +2 -2
  39. package/src/web/components/form/switch/index.jsx +4 -9
  40. package/src/web/components/form/textarea/index.jsx +4 -12
  41. package/src/web/components/form/uploader/index.css +15 -0
  42. package/src/web/components/form/uploader/index.jsx +2 -2
  43. package/src/web/components/form/uploader/uploader.h5.jsx +237 -0
  44. package/src/web/components/form/uploader/{uploaderPc.jsx → uploader.pc.jsx} +76 -58
  45. package/src/web/components/image/image.jsx +79 -5
  46. package/src/web/components/image/index.css +18 -0
  47. package/src/web/components/image/index.jsx +1 -0
  48. package/src/web/components/index.js +26 -58
  49. package/src/web/components/richTextView/index.css +0 -10
  50. package/src/web/components/richTextView/index.jsx +1 -12
  51. package/src/web/components/tabs/{index.js → index.jsx} +3 -3
  52. package/src/web/components/tabs/{tabsH5.js → tabs.h5.jsx} +9 -47
  53. package/src/web/components/tabs/{tabsPc.js → tabs.pc.jsx} +13 -47
  54. package/src/web/components/uploaderView/index.jsx +1 -1
  55. package/src/web/index.js +2 -3
  56. package/src/web/utils/isObjectEqual.js +10 -1
  57. package/src/web/utils/useSyncValue.js +14 -0
  58. package/src/web/weda-ui.css +8 -0
  59. package/src/configs/components/markdown.json +0 -17
  60. package/src/mp/components/markdown/index.js +0 -27
  61. package/src/mp/components/markdown/index.json +0 -6
  62. package/src/mp/components/markdown/index.wxml +0 -1
  63. package/src/mp/components/markdown/towxml/audio-player/Audio.js +0 -99
  64. package/src/mp/components/markdown/towxml/audio-player/audio-player.js +0 -102
  65. package/src/mp/components/markdown/towxml/audio-player/audio-player.json +0 -5
  66. package/src/mp/components/markdown/towxml/audio-player/audio-player.wxml +0 -14
  67. package/src/mp/components/markdown/towxml/audio-player/audio-player.wxss +0 -175
  68. package/src/mp/components/markdown/towxml/audio-player/loading.svg +0 -1
  69. package/src/mp/components/markdown/towxml/config.js +0 -285
  70. package/src/mp/components/markdown/towxml/decode.js +0 -26
  71. package/src/mp/components/markdown/towxml/decode.json +0 -12
  72. package/src/mp/components/markdown/towxml/decode.wxml +0 -1
  73. package/src/mp/components/markdown/towxml/decode.wxss +0 -0
  74. package/src/mp/components/markdown/towxml/img/img.js +0 -98
  75. package/src/mp/components/markdown/towxml/img/img.json +0 -3
  76. package/src/mp/components/markdown/towxml/img/img.wxml +0 -1
  77. package/src/mp/components/markdown/towxml/img/img.wxss +0 -0
  78. package/src/mp/components/markdown/towxml/index.js +0 -19
  79. package/src/mp/components/markdown/towxml/latex/latex.js +0 -53
  80. package/src/mp/components/markdown/towxml/latex/latex.json +0 -5
  81. package/src/mp/components/markdown/towxml/latex/latex.wxml +0 -1
  82. package/src/mp/components/markdown/towxml/latex/latex.wxss +0 -0
  83. package/src/mp/components/markdown/towxml/parse/highlight/highlight.js +0 -729
  84. package/src/mp/components/markdown/towxml/parse/highlight/index.js +0 -7
  85. package/src/mp/components/markdown/towxml/parse/highlight/languages/bash.js +0 -91
  86. package/src/mp/components/markdown/towxml/parse/highlight/languages/c-like.js +0 -244
  87. package/src/mp/components/markdown/towxml/parse/highlight/languages/c.js +0 -20
  88. package/src/mp/components/markdown/towxml/parse/highlight/languages/css.js +0 -138
  89. package/src/mp/components/markdown/towxml/parse/highlight/languages/dart.js +0 -135
  90. package/src/mp/components/markdown/towxml/parse/highlight/languages/go.js +0 -57
  91. package/src/mp/components/markdown/towxml/parse/highlight/languages/htmlbars.js +0 -79
  92. package/src/mp/components/markdown/towxml/parse/highlight/languages/java.js +0 -126
  93. package/src/mp/components/markdown/towxml/parse/highlight/languages/javascript.js +0 -263
  94. package/src/mp/components/markdown/towxml/parse/highlight/languages/json.js +0 -51
  95. package/src/mp/components/markdown/towxml/parse/highlight/languages/less.js +0 -177
  96. package/src/mp/components/markdown/towxml/parse/highlight/languages/nginx.js +0 -103
  97. package/src/mp/components/markdown/towxml/parse/highlight/languages/php.js +0 -152
  98. package/src/mp/components/markdown/towxml/parse/highlight/languages/python-repl.js +0 -27
  99. package/src/mp/components/markdown/towxml/parse/highlight/languages/python.js +0 -146
  100. package/src/mp/components/markdown/towxml/parse/highlight/languages/scss.js +0 -137
  101. package/src/mp/components/markdown/towxml/parse/highlight/languages/shell.js +0 -23
  102. package/src/mp/components/markdown/towxml/parse/highlight/languages/typescript.js +0 -198
  103. package/src/mp/components/markdown/towxml/parse/highlight/languages/xml.js +0 -143
  104. package/src/mp/components/markdown/towxml/parse/highlight/style/github.wxss +0 -99
  105. package/src/mp/components/markdown/towxml/parse/highlight/style/monokai.wxss +0 -70
  106. package/src/mp/components/markdown/towxml/parse/index.js +0 -106
  107. package/src/mp/components/markdown/towxml/parse/markdown/index.js +0 -53
  108. package/src/mp/components/markdown/towxml/parse/markdown/markdown.js +0 -5834
  109. package/src/mp/components/markdown/towxml/parse/markdown/plugins/emoji.js +0 -1773
  110. package/src/mp/components/markdown/towxml/parse/markdown/plugins/ins.js +0 -120
  111. package/src/mp/components/markdown/towxml/parse/markdown/plugins/latex.js +0 -193
  112. package/src/mp/components/markdown/towxml/parse/markdown/plugins/mark.js +0 -120
  113. package/src/mp/components/markdown/towxml/parse/markdown/plugins/sub.js +0 -95
  114. package/src/mp/components/markdown/towxml/parse/markdown/plugins/sup.js +0 -95
  115. package/src/mp/components/markdown/towxml/parse/markdown/plugins/todo.js +0 -220
  116. package/src/mp/components/markdown/towxml/parse/markdown/plugins/yuml.js +0 -18
  117. package/src/mp/components/markdown/towxml/parse/parse2/Parser.js +0 -263
  118. package/src/mp/components/markdown/towxml/parse/parse2/Tokenizer.js +0 -507
  119. package/src/mp/components/markdown/towxml/parse/parse2/domhandler/index.js +0 -104
  120. package/src/mp/components/markdown/towxml/parse/parse2/domhandler/node.js +0 -169
  121. package/src/mp/components/markdown/towxml/parse/parse2/entities/decode.js +0 -54
  122. package/src/mp/components/markdown/towxml/parse/parse2/entities/decode_codepoint.js +0 -19
  123. package/src/mp/components/markdown/towxml/parse/parse2/entities/encode.js +0 -54
  124. package/src/mp/components/markdown/towxml/parse/parse2/entities/index.js +0 -30
  125. package/src/mp/components/markdown/towxml/parse/parse2/entities/maps/decode.js +0 -31
  126. package/src/mp/components/markdown/towxml/parse/parse2/entities/maps/entities.js +0 -2128
  127. package/src/mp/components/markdown/towxml/parse/parse2/entities/maps/legacy.js +0 -109
  128. package/src/mp/components/markdown/towxml/parse/parse2/entities/maps/xml.js +0 -2
  129. package/src/mp/components/markdown/towxml/parse/parse2/index.js +0 -8
  130. package/src/mp/components/markdown/towxml/style/main.wxss +0 -378
  131. package/src/mp/components/markdown/towxml/style/theme/dark.wxss +0 -73
  132. package/src/mp/components/markdown/towxml/style/theme/light.wxss +0 -63
  133. package/src/mp/components/markdown/towxml/table/table.js +0 -11
  134. package/src/mp/components/markdown/towxml/table/table.json +0 -6
  135. package/src/mp/components/markdown/towxml/table/table.wxml +0 -24
  136. package/src/mp/components/markdown/towxml/table/table.wxss +0 -0
  137. package/src/mp/components/markdown/towxml/todogroup/todogroup.js +0 -19
  138. package/src/mp/components/markdown/towxml/todogroup/todogroup.json +0 -6
  139. package/src/mp/components/markdown/towxml/todogroup/todogroup.wxml +0 -13
  140. package/src/mp/components/markdown/towxml/todogroup/todogroup.wxss +0 -3
  141. package/src/mp/components/markdown/towxml/towxml.js +0 -17
  142. package/src/mp/components/markdown/towxml/towxml.json +0 -6
  143. package/src/mp/components/markdown/towxml/towxml.wxml +0 -5
  144. package/src/mp/components/markdown/towxml/towxml.wxss +0 -8
  145. package/src/mp/components/markdown/towxml/yuml/yuml.js +0 -51
  146. package/src/mp/components/markdown/towxml/yuml/yuml.json +0 -5
  147. package/src/mp/components/markdown/towxml/yuml/yuml.wxml +0 -5
  148. package/src/mp/components/markdown/towxml/yuml/yuml.wxss +0 -0
  149. package/src/web/components/form/uploader/uploaderH5.jsx +0 -192
  150. package/src/web/components/markdown/index.jsx +0 -40
@@ -0,0 +1,237 @@
1
+ import * as PropTypes from 'prop-types';
2
+ import * as React from 'react';
3
+ import weui from '../../../utils/weui';
4
+ import classNames from '../../../utils/classnames';
5
+ import { getCloudInstance, getTempFileURL } from '../../../utils/tcb';
6
+ import isObjectEqual from '../../../utils/isObjectEqual';
7
+ import { useSyncValue } from '../../../utils/useSyncValue';
8
+ import { isCloudFileID } from '../../../utils/platform';
9
+ import { IMAGE_TYPES } from './uploader.pc';
10
+
11
+ const uploadPath = 'weda-uploader';
12
+ /**
13
+ * H5端
14
+ */
15
+ export function ImageUploaderH5({
16
+ title,
17
+ maxUploadCount,
18
+ maxSize = 10,
19
+ acceptTypes,
20
+ className,
21
+ id,
22
+ events,
23
+ layout,
24
+ defaultValue,
25
+ single = false,
26
+ onChange,
27
+ style,
28
+ }) {
29
+ const cls = classNames({
30
+ 'weda-ui': true,
31
+ 'weui-cells': true,
32
+ 'weui-cells_form': true,
33
+ [className]: className,
34
+ });
35
+
36
+ // 上传中
37
+ const [uploading, setUploading] = React.useState(false);
38
+ //上传进度
39
+ const [progress, setProgress] = React.useState(0);
40
+ const [inputValue, setInputValue] = useSyncValue(defaultValue, isObjectEqual);
41
+ const fileIdList = React.useMemo(() => {
42
+ if( typeof inputValue === 'string') {
43
+ // single = true 传入的是字符串
44
+ return [inputValue].filter(i => i.length > 0); // 排除空串
45
+ }
46
+ if(Array.isArray(inputValue)) {
47
+ return inputValue;
48
+ }
49
+ return [];
50
+ }, [inputValue]);
51
+
52
+ const finalMaxImgCount = React.useMemo(() => {
53
+ if(single) return 1;
54
+ return maxUploadCount;
55
+ }, [single, maxUploadCount]);
56
+
57
+ const deleteFile = (url) => {
58
+ if(single) {
59
+ setInputValue('');
60
+ return;
61
+ }
62
+ setInputValue((list) => list.filter(f => f !== url));
63
+ };
64
+ React.useEffect(() => {
65
+ if (single) {
66
+ const file = fileIdList[0] || '';
67
+ file && onChange && onChange(file);
68
+ events.change && events.change({ value: file });
69
+ } else {
70
+ onChange && onChange(fileIdList);
71
+ events.change && events.change({ value: fileIdList });
72
+ }
73
+ }, [fileIdList]);
74
+ const onProgress = (progressEvent) => {
75
+ let percentCompleted = 0;
76
+ try {
77
+ percentCompleted = Math.round(
78
+ (progressEvent.loaded * 100) / progressEvent.total
79
+ );
80
+ percentCompleted < 100 ? percentCompleted : 100;
81
+ } catch (e) {}
82
+ setProgress(percentCompleted);
83
+ };
84
+ const uploadToTcb = (file) => {
85
+ setUploading(true);
86
+ getCloudInstance().then(async (tcb) => {
87
+ try {
88
+ const fileType = file.type.split('/')?.[1];
89
+ const cloudPath = `${uploadPath}/uploader-${Date.now()}.${fileType}`;
90
+ const { fileID } = await tcb.uploadFile({
91
+ cloudPath,
92
+ filePath: file,
93
+ onUploadProgress: onProgress,
94
+
95
+ });
96
+ fileID && setInputValue((list) => [...list, fileID]);
97
+ fileID && events.success && events.success({ value: fileID, file });
98
+ } catch (err) {
99
+ events.error && events.error(err);
100
+ } finally {
101
+ setUploading(false);
102
+ setProgress(0);
103
+ }
104
+ });
105
+ };
106
+
107
+ const accepts = React.useMemo(() => {
108
+ return acceptTypes.includes('image/*') || acceptTypes.length === 0
109
+ ? IMAGE_TYPES
110
+ : Array.from(new Set(acceptTypes));
111
+ }, [acceptTypes]);
112
+
113
+ return (
114
+ <div className={cls} id={id} style={style}>
115
+ <div className="weui-cell">
116
+ <div className="weui-cell__bd">
117
+ <div className={classNames("weui-uploader", layout)}>
118
+ <div className={classNames("weui-uploader__hd", layout)}>
119
+ <p className="weui-uploader__title">{title}</p>
120
+ <div className="weui-uploader__info">
121
+ <span id="uploadCount">{fileIdList.length}</span>
122
+ {`/${finalMaxImgCount}`}
123
+ </div>
124
+ </div>
125
+ <div className="weui-uploader__bd">
126
+ <ul className="weui-uploader__files" id="uploaderFiles">
127
+ {(fileIdList ?? []).map(f => <SingleImage key={f} src={f} deleteBySrc={deleteFile} />)}
128
+ {uploading &&
129
+ <li className="weui-uploader__file weui-uploader__file_status" >
130
+ <div className="weui-uploader__file-content">
131
+ {progress}%
132
+ </div>
133
+ </li>}
134
+ </ul>
135
+ {(fileIdList.length < maxUploadCount ||
136
+ (single && fileIdList.length < 1)) && ( // single 模式时,仅当数组为空时显示
137
+ <div className="weui-uploader__input-box">
138
+ <input
139
+ id="uploaderInput"
140
+ className="weui-uploader__input"
141
+ type="file"
142
+ accept={accepts.join(',')}
143
+ multiple
144
+ onChange={e => {
145
+ const files = [...e.target.files];
146
+ if (files.some(f => f.size > maxSize * 1024 * 1024)) {
147
+ weui.alert('请上传不超过10M的图片');
148
+ return false;
149
+ }
150
+
151
+ if (files.length > finalMaxImgCount) {
152
+ // 防止一下子选择过多文件
153
+ weui.alert(`最多只能上传${finalMaxImgCount}张图片,请重新选择`);
154
+ return false;
155
+ }
156
+ if (fileIdList.length + files.length > finalMaxImgCount) {
157
+ weui.alert(`最多只能上传${finalMaxImgCount}张图片`);
158
+ return false;
159
+ }
160
+ files.forEach(f => uploadToTcb(f));
161
+ }}
162
+ />
163
+ </div>
164
+ )}
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ </div>
170
+ );
171
+ }
172
+
173
+ function SingleImage({src, deleteBySrc}) {
174
+ const [error, setError] = React.useState(false);
175
+ const cls = classNames({
176
+ 'weui-uploader__file': true,
177
+ });
178
+ const [realSrc, setRealSrc] = React.useState('');
179
+ React.useEffect(() => {
180
+ const getSrc = async () => {
181
+ try {
182
+ const _src = await getTempFileURL(src);
183
+ setRealSrc(_src);
184
+ return _src;
185
+ } catch (e) {
186
+ setError(true);
187
+ console.error('图片加载失败');
188
+ }
189
+ };
190
+ if(isCloudFileID(src)) {
191
+ getSrc();
192
+ } else {
193
+ setRealSrc(src);
194
+ }
195
+ }, [src]);
196
+ const imgStyle = {
197
+ backgroundImage: `url(${realSrc})`
198
+ };
199
+ const showGallery = () => {
200
+ const gallery = weui.gallery(realSrc, {
201
+ onDelete: function() {
202
+ deleteBySrc(src);
203
+ gallery.hide();
204
+ }
205
+ });
206
+ };
207
+
208
+ return (
209
+ <li className={cls} style={imgStyle} onClick={showGallery}>
210
+ {
211
+ error || status ?
212
+ <div className="weui-uploader__file-content">
213
+ { error ? <i role="img" aria-label="错误" className="weui-icon-warn"></i> : <i className="weui-loading" style={{width: 30, height: 30}}></i> }
214
+ </div>
215
+ : false
216
+ }
217
+ </li>
218
+ );
219
+ }
220
+ SingleImage.propTypes = {
221
+ src: PropTypes.string,
222
+ deleteBySrc: PropTypes.func
223
+ };
224
+ ImageUploaderH5.propTypes = {
225
+ id: PropTypes.string,
226
+ title: PropTypes.string,
227
+ className: PropTypes.string, // 传入类
228
+ maxSize: PropTypes.number,
229
+ acceptTypes: PropTypes.array,
230
+ maxUploadCount: PropTypes.number, // 【上传图片最大数量】
231
+ events: PropTypes.objectOf(PropTypes.func), // 事件
232
+ style: PropTypes.object,
233
+ layout: PropTypes.oneOf(['horizontal', 'vertical']),
234
+ defaultValue: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), // 初始值,该参数需配合 formily 使用
235
+ single: PropTypes.bool, // 单张上传还是多张上传,对应 onChange 参数为字符串还是字符串数组,value 在处理过程统一转为字符串数组
236
+ onChange: PropTypes.objectOf(PropTypes.func), // 值变化,该参数需配合 formily 使用
237
+ };
@@ -18,7 +18,7 @@ import * as PropTypes from 'prop-types';
18
18
  // 默认组件类前缀
19
19
  export const CLASS_PREFIX = 'weda-uploader-pc';
20
20
  // 默认图片类型
21
- const IMAGE_TYPES = [
21
+ export const IMAGE_TYPES = [
22
22
  'image/jpg',
23
23
  'image/png',
24
24
  'image/tif',
@@ -31,7 +31,15 @@ const IMAGE_TYPES = [
31
31
  * 上传图片-官方组件
32
32
  */
33
33
  // eslint-disable-next-line react/prop-types
34
- export function UploaderPC({layout, className, id, style,title,tips, ...props }) {
34
+ export function UploaderPC({
35
+ layout,
36
+ className,
37
+ id,
38
+ style,
39
+ title,
40
+ tips,
41
+ ...props
42
+ }) {
35
43
  const cls = classNames({
36
44
  'weda-ui': true,
37
45
  [CLASS_PREFIX]: true,
@@ -40,25 +48,24 @@ export function UploaderPC({layout, className, id, style,title,tips, ...props })
40
48
  });
41
49
  return (
42
50
  <div className={cls} id={id} style={style}>
43
- <div className={`${CLASS_PREFIX}__header`}>
44
- {title && <div className={`${CLASS_PREFIX}__title`}>{title}</div>}
45
- {tips && (
46
- <div className={`${CLASS_PREFIX}__description`}>{tips || ''}</div>
47
- )}
48
- </div>
49
- <UploaderPCInner {...props} />
51
+ <div className={`${CLASS_PREFIX}__header`}>
52
+ {title && <div className={`${CLASS_PREFIX}__title`}>{title}</div>}
53
+ {tips && (
54
+ <div className={`${CLASS_PREFIX}__description`}>{tips || ''}</div>
55
+ )}
56
+ </div>
57
+ <UploaderPCInner {...props} />
50
58
  </div>
51
- );
59
+ );
52
60
  }
53
61
 
54
-
55
62
  export function UploaderPCInner(props) {
56
63
  let {
57
64
  tips = '',
58
65
  btnTitle = '上传图片',
59
66
  maxUploadCount = 9,
60
67
  maxSize = 10,
61
- value, // 需要兼容 cloud:和https: 协议,需要兼容 字符串和字符串数组
68
+ value: defaultValue, // 需要兼容 cloud:和https: 协议,需要兼容 字符串和字符串数组
62
69
  acceptTypes = IMAGE_TYPES,
63
70
  uploadPath = 'weda-uploader',
64
71
  uploadFileName = 'image',
@@ -67,24 +74,25 @@ export function UploaderPCInner(props) {
67
74
  onChange,
68
75
  } = props;
69
76
 
70
-
71
-
72
77
  // 上传中
73
78
  const [uploading, setUploading] = React.useState(false);
74
79
  //上传进度
75
80
  const [progress, setProgress] = React.useState(0);
76
81
  // 文件列表
77
82
  const [fileIDList, setfileIDList] = React.useState([]);
83
+ const prevValueRef = React.useRef();
78
84
  React.useEffect(() => {
79
- let initialValue = []
80
- .concat(value)
81
- .filter((d) => typeof d === 'string' && d !== '');
82
- if (single) {
83
- maxUploadCount = 1;
84
- initialValue = initialValue[0] ? [initialValue[0]] : [];
85
+ if (prevValueRef.current !== defaultValue) {
86
+ let initialValue = []
87
+ .concat(defaultValue)
88
+ .filter((d) => typeof d === 'string' && d !== '');
89
+ if (single) {
90
+ initialValue = initialValue[0] ? [initialValue[0]] : [];
91
+ }
92
+ setfileIDList(initialValue);
93
+ prevValueRef.current = defaultValue;
85
94
  }
86
- setfileIDList(initialValue);
87
- }, [value, maxUploadCount, single]);
95
+ }, [defaultValue, maxUploadCount, single]);
88
96
  const fileRef = React.useRef(fileIDList);
89
97
 
90
98
  // 值变化事件
@@ -159,7 +167,7 @@ export function UploaderPCInner(props) {
159
167
  const deleteHandle = (fileID) => {
160
168
  setfileIDList((list) => list.filter((d) => d !== fileID));
161
169
  };
162
-
170
+
163
171
  // 转换后的属性
164
172
  const extraProps = {};
165
173
  extraProps['accept'] =
@@ -171,42 +179,52 @@ export function UploaderPCInner(props) {
171
179
 
172
180
  return (
173
181
  <ConfigProvider classPrefix="wedatea2td">
174
- <div className="_weda-fn-upload-result">
175
- {fileIDList.map((d) => (
176
- <div className="_weda-fn-upload-result__item" key={d}>
177
- <TcbImage fileID={d} />
178
- <div className="_weda-fn-upload-result__op">
179
- <Button
180
- onClick={() => deleteHandle(d)}
181
- className={`${CLASS_PREFIX}__btn`}
182
- >
183
- 删除
184
- </Button>
185
- </div>
182
+ <div className="_weda-fn-upload-result">
183
+ {fileIDList.map((d) => (
184
+ <div className="_weda-fn-upload-result__item" key={d}>
185
+ <TcbImage fileID={d} />
186
+ <div className="_weda-fn-upload-result__op">
187
+ <Button
188
+ onClick={() => deleteHandle(d)}
189
+ className={`${CLASS_PREFIX}__btn`}
190
+ >
191
+ 删除
192
+ </Button>
186
193
  </div>
187
- ))}
188
- {uploading && (
189
- <div className="_weda-fn-upload-result__item">
190
- <div className="_weda-fn-upload-result__status" key="_place_image">
191
- <Icon type="loading" />
192
- {!!progress && <span className="wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset">上传{progress}%...</span>}
193
- </div>
194
+ </div>
195
+ ))}
196
+ {uploading && (
197
+ <div className="_weda-fn-upload-result__item">
198
+ <div className="_weda-fn-upload-result__status" key="_place_image">
199
+ <Icon type="loading" />
200
+ {!!progress && (
201
+ <span className="wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset">
202
+ 上传{progress}%...
203
+ </span>
204
+ )}
194
205
  </div>
195
- )}
196
- <div className={`${CLASS_PREFIX}__input-box`}>
197
- {fileIDList.length < maxUploadCount &&
198
- <Upload {...extraProps} beforeUpload={beforeHandle}>
206
+ </div>
207
+ )}
208
+ <div className={`${CLASS_PREFIX}__input-box`}>
209
+ {(fileIDList.length < maxUploadCount ||
210
+ (single && fileIDList.length < 1)) && ( // single 模式时,仅当数组为空时显示
211
+ <Upload {...extraProps} beforeUpload={beforeHandle}>
199
212
  <li className="_weda-fn-upload-result__item _weda-fn-upload-result__item--upload">
200
- <div className="_weda-fn-upload-result__status">
201
- <i className="wedatea2td-icon wedatea2td-icon-plus" role="img" aria-label="plus"></i>
202
- <span className="wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset">{btnTitle}</span>
203
- </div>
204
- </li>
205
- </Upload>
206
- }
207
- </div>
213
+ <div className="_weda-fn-upload-result__status">
214
+ <i
215
+ className="wedatea2td-icon wedatea2td-icon-plus"
216
+ role="img"
217
+ aria-label="plus"
218
+ ></i>
219
+ <span className="wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset">
220
+ {btnTitle}
221
+ </span>
222
+ </div>
223
+ </li>
224
+ </Upload>
225
+ )}
208
226
  </div>
209
-
227
+ </div>
210
228
  </ConfigProvider>
211
229
  );
212
230
  }
@@ -224,7 +242,7 @@ export const TcbImage = (props) => {
224
242
  const _src = await getTempFileURL(fileID);
225
243
  _src ? setSrc(_src) : setIsError(true);
226
244
  } catch (e) {
227
- message.error('图片加载失败');
245
+ message.error({ content: '图片加载失败' });
228
246
  }
229
247
  };
230
248
  isCloudFileID(fileID) ? getSrc() : setSrc(fileID);
@@ -278,11 +296,11 @@ UploaderPCInner.propTypes = {
278
296
  style: PropTypes.object,
279
297
  id: PropTypes.string,
280
298
  layout: PropTypes.oneOf(['horizontal', 'vertical']),
281
- disabled: PropTypes.bool
299
+ disabled: PropTypes.bool,
282
300
  };
283
301
 
284
302
  TcbImage.propTypes = {
285
303
  fileID: PropTypes.string, // 云存储id
286
304
  isZoom: PropTypes.bool, // 是否点击放大
287
305
  onError: PropTypes.func, // 图片显示错误事件
288
- };
306
+ };
@@ -1,7 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import * as PropTypes from 'prop-types';
3
- import { usePlatform } from '../../utils/platform';
4
3
  import { ConfigProvider, ImagePreview } from 'tea-component';
4
+ import { usePlatform } from '../../utils/platform';
5
+ import { useGesture } from '@use-gesture/react';
5
6
 
6
7
  ImageInner.propTypes = {
7
8
  objectFit: PropTypes.string,
@@ -11,17 +12,21 @@ ImageInner.propTypes = {
11
12
  src: PropTypes.string,
12
13
  alt: PropTypes.string,
13
14
  lazyLoad: PropTypes.bool,
15
+ isError: PropTypes.bool,
14
16
  setIsError: PropTypes.func,
15
17
  maskClosable: PropTypes.bool,
16
18
  imgPreview: PropTypes.bool
17
19
  };
18
20
 
21
+ const failImgBase64 = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIiBmaWxsPSJub25lIj4KICA8cGF0aCBkPSJNMjUuMzIgMTYuMzU5N0MyNi4wNzY0IDE2LjM1OTcgMjYuODI1NCAxNi41MDg3IDI3LjUyNDMgMTYuNzk4MUMyOC4yMjMxIDE3LjA4NzYgMjguODU4MSAxNy41MTE5IDI5LjM5MjkgMTguMDQ2OEMyOS45Mjc4IDE4LjU4MTYgMzAuMzUyMSAxOS4yMTY2IDMwLjY0MTYgMTkuOTE1NEMzMC45MzEgMjAuNjE0MyAzMS4wOCAyMS4zNjMzIDMxLjA4IDIyLjExOTdDMzEuMDggMjIuODc2MSAzMC45MzEgMjMuNjI1MSAzMC42NDE2IDI0LjMyMzlDMzAuMzUyMSAyNS4wMjI4IDI5LjkyNzggMjUuNjU3OCAyOS4zOTI5IDI2LjE5MjZDMjguODU4MSAyNi43Mjc1IDI4LjIyMzEgMjcuMTUxOCAyNy41MjQzIDI3LjQ0MTJDMjYuODI1NCAyNy43MzA3IDI2LjA3NjQgMjcuODc5NyAyNS4zMiAyNy44Nzk3QzIzLjc5MjQgMjcuODc5NyAyMi4zMjczIDI3LjI3MjggMjEuMjQ3MSAyNi4xOTI2QzIwLjE2NjkgMjUuMTEyNCAxOS41NiAyMy42NDczIDE5LjU2IDIyLjExOTdDMTkuNTYgMjAuNTkyIDIwLjE2NjkgMTkuMTI3IDIxLjI0NzEgMTguMDQ2OEMyMi4zMjczIDE2Ljk2NjUgMjMuNzkyNCAxNi4zNTk3IDI1LjMyIDE2LjM1OTdaTTI4IDMuNTU5NjlWMTQuODc2OEMyNy4xNzc3IDE0LjU4NjYgMjYuMTkyIDE0LjQzODggMjUuMzIgMTQuNDM5N0MyNC4wMzEgMTQuNDM5NyAyMi44MTU3IDE0Ljc1NzEgMjEuNzQ4OCAxNS4zMTg0TDIwLjc5NTIgMTMuMTU5N0wxNi4wMjU5IDIwLjAyNzVMOC40NDU3NiAxNi40NDFMMy41NiAyMy4zOTk3SDE3Ljc0NjJDMTcuOTg2NyAyNC44MjkgMTguNjI4MiAyNi4xNjA2IDE5LjU5NTggMjcuMjM5N0gxVjMuNTU5NjlIMjhaTTI1Ljk2IDI0LjAzOTdIMjQuNjhWMjUuMzE5N0gyNS45NlYyNC4wMzk3Wk0yNS45NiAxOC45MTk3SDI0LjY4VjIzLjM5OTdIMjUuOTZWMTguOTE5N1pNNi4xMiAxMC41OTk3QzYuMTIgMTEuOTk4MSA3LjE5OTA0IDEzLjEwODUgOC42MDc2OCAxMy4xNTg0QzEwLjAyMDggMTMuMjA3NyAxMS4yNCAxMi4wNDggMTEuMjQgMTAuNTk5N0MxMS4yNCA5LjI0NjA5IDEwLjA2NDMgOC4wODU3NyA4Ljc1MjMyIDguMDQwOTdDNy4yOTU2OCA3Ljk5MTY5IDYuMTIgOS4xNTEzNyA2LjEyIDEwLjU5OTdaIiBmaWxsPSIjQkNDNEQwIj48L3BhdGg+Cjwvc3ZnPgo=';
22
+
19
23
  export function ImageInner({
20
24
  objectFit,
21
25
  style,
22
26
  className,
23
27
  alt,
24
28
  src,
29
+ isError,
25
30
  setIsError,
26
31
  events,
27
32
  lazyLoad,
@@ -35,7 +40,55 @@ export function ImageInner({
35
40
  setImgShow(false);
36
41
  }
37
42
  };
38
- if(platform === 'h5' || !imgPreview) {
43
+
44
+ const [showHeight, setShowHeight] = React.useState(0);
45
+ const realWidth = React.useRef(0);
46
+ const realHeight = React.useRef(0);
47
+ const [offsetHeight, setOffsetHeight] = React.useState(0);
48
+ const [translateX, setTranslateX]= React.useState(0);
49
+ const [translateY, setTranslateY]= React.useState(0);
50
+ const [previewScale, setPreviewScale] = React.useState(1);
51
+ React.useEffect(() => {
52
+ // 防止触发浏览器的放大缩小
53
+ const handler = e => e.preventDefault();
54
+ document.addEventListener('gesturestart', handler);
55
+ document.addEventListener('gesturechange', handler);
56
+ return () => {
57
+ document.removeEventListener('gesturestart', handler);
58
+ document.removeEventListener('gesturechange', handler);
59
+ };
60
+ }, []);
61
+
62
+ const bind = useGesture({
63
+ onClick: ({event}) => {
64
+ // 防止冒泡出发关闭预览
65
+ event.stopPropagation();
66
+ },
67
+ onPinch: ({offset}) => {
68
+ const [s] = offset;
69
+ setPreviewScale(s);
70
+ },
71
+ onDrag: ({offset, event}) => {
72
+ event.stopPropagation();
73
+ const [x, y] = offset;
74
+ setTranslateX(x);
75
+ setTranslateY(y);
76
+
77
+ },
78
+ }, {
79
+ drag: {
80
+ delay: true,
81
+ preventDefault: true,
82
+ },
83
+ pinch: {
84
+ scaleBounds: {min: 0.6, max: 5},
85
+ pointer: {
86
+ touch: true
87
+ }
88
+ }
89
+ });
90
+
91
+ if(platform === 'h5' || !imgPreview || isError) {
39
92
  return (
40
93
  <>
41
94
  <img
@@ -47,6 +100,11 @@ export function ImageInner({
47
100
  alt={alt}
48
101
  src={src}
49
102
  onLoad={(e) => {
103
+ /* @type {HTMLImageElement} */
104
+ const img = e.target;
105
+ const {naturalHeight, naturalWidth} = img;
106
+ realHeight.current = naturalHeight;
107
+ realWidth.current = naturalWidth;
50
108
  setIsError(false);
51
109
  events.load && events.load({}, { originEvent: e });
52
110
  }}
@@ -56,7 +114,16 @@ export function ImageInner({
56
114
  }}
57
115
  onClick={
58
116
  () => {
59
- if(imgPreview) {
117
+ if(imgPreview && !isError) {
118
+ setTranslateX(0);
119
+ setTranslateY(0);
120
+ setPreviewScale(1);
121
+ const windowHeight = window.innerHeight;
122
+ const windowWidth = window.innerWidth;
123
+ const ratio = (realWidth.current / realHeight.current);
124
+ const height = windowWidth / ratio;
125
+ setOffsetHeight(windowHeight / 2 - (height / 2));
126
+ setShowHeight(height);
60
127
  setImgShow(true);
61
128
  }
62
129
  }
@@ -68,8 +135,15 @@ export function ImageInner({
68
135
  <div onClick={() => setImgShow(false)} className="weda-img-modal-close-btn">
69
136
  <i className="weui-icon-clear" style={{color: 'white'}}></i>
70
137
  </div>
71
- <div className="weda-img-preview" style={{
72
- backgroundImage: `url(${src})`
138
+
139
+ {/* eslint-disable-next-line react/jsx-props-no-spreading */}
140
+ <div {...bind()} className="weda-img-preview" style={{
141
+ touchAction: 'none',
142
+ backgroundImage: `url(${src})`,
143
+ width: '100%',
144
+ height: showHeight,
145
+ marginTop: offsetHeight,
146
+ transform: `translate(${translateX}px, ${translateY}px) scale(${previewScale})`
73
147
  }}></div>
74
148
  </div>
75
149
  }
@@ -11,6 +11,7 @@
11
11
  left: 0;
12
12
  right: 0;
13
13
  background-color: black;
14
+ z-index: 99;
14
15
  }
15
16
 
16
17
  .weda-img-preview {
@@ -22,6 +23,7 @@
22
23
  right: 0;
23
24
  top: 0;
24
25
  bottom: 0;
26
+ z-index: 150;
25
27
  }
26
28
 
27
29
  .weda-img-modal-close-btn {
@@ -32,3 +34,19 @@
32
34
  z-index: 99;
33
35
  color: white;
34
36
  }
37
+
38
+ .weda-image.weda-image-error {
39
+ position: relative;
40
+ display: inline-block;
41
+ }
42
+
43
+ .weda-image:not([src]):before,
44
+ .weda-image-error::before {
45
+ content: '';
46
+ background: #f5f5f5 url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIiBmaWxsPSJub25lIj4KICA8cGF0aCBkPSJNMjUuMzIgMTYuMzU5N0MyNi4wNzY0IDE2LjM1OTcgMjYuODI1NCAxNi41MDg3IDI3LjUyNDMgMTYuNzk4MUMyOC4yMjMxIDE3LjA4NzYgMjguODU4MSAxNy41MTE5IDI5LjM5MjkgMTguMDQ2OEMyOS45Mjc4IDE4LjU4MTYgMzAuMzUyMSAxOS4yMTY2IDMwLjY0MTYgMTkuOTE1NEMzMC45MzEgMjAuNjE0MyAzMS4wOCAyMS4zNjMzIDMxLjA4IDIyLjExOTdDMzEuMDggMjIuODc2MSAzMC45MzEgMjMuNjI1MSAzMC42NDE2IDI0LjMyMzlDMzAuMzUyMSAyNS4wMjI4IDI5LjkyNzggMjUuNjU3OCAyOS4zOTI5IDI2LjE5MjZDMjguODU4MSAyNi43Mjc1IDI4LjIyMzEgMjcuMTUxOCAyNy41MjQzIDI3LjQ0MTJDMjYuODI1NCAyNy43MzA3IDI2LjA3NjQgMjcuODc5NyAyNS4zMiAyNy44Nzk3QzIzLjc5MjQgMjcuODc5NyAyMi4zMjczIDI3LjI3MjggMjEuMjQ3MSAyNi4xOTI2QzIwLjE2NjkgMjUuMTEyNCAxOS41NiAyMy42NDczIDE5LjU2IDIyLjExOTdDMTkuNTYgMjAuNTkyIDIwLjE2NjkgMTkuMTI3IDIxLjI0NzEgMTguMDQ2OEMyMi4zMjczIDE2Ljk2NjUgMjMuNzkyNCAxNi4zNTk3IDI1LjMyIDE2LjM1OTdaTTI4IDMuNTU5NjlWMTQuODc2OEMyNy4xNzc3IDE0LjU4NjYgMjYuMTkyIDE0LjQzODggMjUuMzIgMTQuNDM5N0MyNC4wMzEgMTQuNDM5NyAyMi44MTU3IDE0Ljc1NzEgMjEuNzQ4OCAxNS4zMTg0TDIwLjc5NTIgMTMuMTU5N0wxNi4wMjU5IDIwLjAyNzVMOC40NDU3NiAxNi40NDFMMy41NiAyMy4zOTk3SDE3Ljc0NjJDMTcuOTg2NyAyNC44MjkgMTguNjI4MiAyNi4xNjA2IDE5LjU5NTggMjcuMjM5N0gxVjMuNTU5NjlIMjhaTTI1Ljk2IDI0LjAzOTdIMjQuNjhWMjUuMzE5N0gyNS45NlYyNC4wMzk3Wk0yNS45NiAxOC45MTk3SDI0LjY4VjIzLjM5OTdIMjUuOTZWMTguOTE5N1pNNi4xMiAxMC41OTk3QzYuMTIgMTEuOTk4MSA3LjE5OTA0IDEzLjEwODUgOC42MDc2OCAxMy4xNTg0QzEwLjAyMDggMTMuMjA3NyAxMS4yNCAxMi4wNDggMTEuMjQgMTAuNTk5N0MxMS4yNCA5LjI0NjA5IDEwLjA2NDMgOC4wODU3NyA4Ljc1MjMyIDguMDQwOTdDNy4yOTU2OCA3Ljk5MTY5IDYuMTIgOS4xNTEzNyA2LjEyIDEwLjU5OTdaIiBmaWxsPSIjQkNDNEQwIj48L3BhdGg+Cjwvc3ZnPgo=') no-repeat center / 50% 50%;
47
+ position: absolute;
48
+ left: 0;
49
+ top: 0;
50
+ width: 100%;
51
+ height: 100%;
52
+ }
@@ -54,6 +54,7 @@ export default function Image({
54
54
  className={cls}
55
55
  alt={alt}
56
56
  src={realSrc}
57
+ isError={isError}
57
58
  setIsError={setIsError}
58
59
  events={events}
59
60
  lazyLoad={lazyLoad}