@cloudbase/weda-ui 3.1.4 → 3.1.6

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.
@@ -7,21 +7,21 @@
7
7
  "default": "标题",
8
8
  "title": "标题",
9
9
  "x-category": "基础属性",
10
- "x-index": 1
10
+ "x-index": 10
11
11
  },
12
12
  "labelVisible": {
13
13
  "type": "boolean",
14
14
  "default": true,
15
15
  "title": "是否显示标题",
16
16
  "x-category": "基础属性",
17
- "x-index": 2
17
+ "x-index": 20
18
18
  },
19
19
  "requiredFlag": {
20
20
  "type": "boolean",
21
21
  "default": false,
22
22
  "title": "是否显示必填标记",
23
23
  "x-category": "基础属性",
24
- "x-index": 3
24
+ "x-index": 30
25
25
  },
26
26
  "layout": {
27
27
  "title": "布局方式",
@@ -38,35 +38,42 @@
38
38
  }
39
39
  ],
40
40
  "x-category": "基础属性",
41
- "x-index": 4
41
+ "x-index": 40
42
42
  },
43
43
  "name": {
44
44
  "type": "string",
45
45
  "default": "formRichText",
46
46
  "title": "提交后台所用字段",
47
47
  "x-category": "基础属性",
48
- "x-index": 5
48
+ "x-index": 50
49
49
  },
50
50
  "value": {
51
51
  "type": "string",
52
52
  "default": "",
53
53
  "title": "初始值",
54
54
  "x-category": "基础属性",
55
- "x-index": 6
55
+ "x-index": 60
56
56
  },
57
57
  "readOnly": {
58
58
  "type": "boolean",
59
59
  "default": false,
60
60
  "title": "是否只读",
61
61
  "x-category": "基础属性",
62
- "x-index": 7
62
+ "display": false,
63
+ "x-index": 70
64
+ },
65
+ "disabled": {
66
+ "type": "boolean",
67
+ "title": "禁用",
68
+ "default": false,
69
+ "x-index": 75
63
70
  },
64
71
  "maxSize": {
65
72
  "type": "number",
66
73
  "default": 10,
67
74
  "title": "单张图片最大(M)",
68
75
  "x-category": "基础属性",
69
- "x-index": 8
76
+ "x-index": 80
70
77
  },
71
78
  "acceptTypes": {
72
79
  "type": "array",
@@ -105,8 +112,9 @@
105
112
  }
106
113
  ]
107
114
  },
115
+ "display": false,
108
116
  "x-category": "基础属性",
109
- "x-index": 9
117
+ "x-index": 90
110
118
  }
111
119
  }
112
120
  },
@@ -27,6 +27,21 @@
27
27
  margin: 5PX 0PX 5PX 0PX !important;
28
28
  }
29
29
 
30
+ .weda-richText .bf-controlbar .control-item.button-indent-increase,
31
+ .weda-richText .bf-controlbar .control-item.button-indent-decrease,
32
+ .weda-richText .bf-controlbar .control-item[data-alignment='left'],
33
+ .weda-richText .bf-controlbar .control-item[data-alignment='center'],
34
+ .weda-richText .bf-controlbar .control-item[data-alignment='right'],
35
+ .weda-richText .bf-controlbar .control-item[data-alignment='justify'],
36
+ .weda-richText .bf-controlbar .control-item.link-editor-dropdown,
37
+ .weda-richText .bf-controlbar .control-item[data-title='清除链接'] {
38
+ margin-top: 0 !important;
39
+ }
40
+
41
+ .weda-richText .weda-formcells__content .weui-cell_form {
42
+ padding-top: 0;
43
+ }
44
+
30
45
  .weda-richText .headings-dropdown {
31
46
  min-width: auto !important;
32
47
  }
@@ -40,11 +55,6 @@
40
55
  min-width: auto !important;
41
56
  }
42
57
 
43
- .weda-richText .weda-formcells__content .weui-cell {
44
- padding-left: 0 !important;
45
- padding-right: 0 !important;
46
- }
47
-
48
58
  .weda-richText {
49
59
  width: 100%;
50
60
  }
@@ -89,5 +99,9 @@
89
99
  }
90
100
 
91
101
  .weda-richText .weda-formcells__content.weui-flex__item {
92
- margin-right: 2.28571rem;
102
+ margin-top: 1.14286rem;
103
+ }
104
+
105
+ .weda-richText .bf-font-size-dropdown {
106
+ min-width: 4.14286rem;
93
107
  }
@@ -21,14 +21,13 @@ declare function RichText({ id, style, className, events, label, labelVisible, v
21
21
  declare namespace RichText {
22
22
  var defaultProps: {
23
23
  events: {};
24
- style: {
25
- width: string;
26
- };
24
+ style: {};
27
25
  label: string;
28
26
  labelVisible: boolean;
29
27
  name: string;
30
28
  value: string;
31
29
  readOnly: boolean;
30
+ disabled: boolean;
32
31
  layout: string;
33
32
  requiredFlag: boolean;
34
33
  maxSize: number;
@@ -1,17 +1,19 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
1
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { useSetState } from '../../utils/useSetState';
3
3
  import classNames from '../../utils/classnames';
4
- import Editor, { convertEditorStateToHTML } from 'kedao';
5
- import { ContentUtils } from 'kedao/lib/utils';
4
+ import Editor, { EditorState, convertEditorStateToHTML } from 'kedao';
5
+ import { insertMedias, handleKeyCommand } from 'kedao/lib/utils';
6
6
  import { createStateFromContent } from 'kedao/lib/editor';
7
- import { getCloudInstance, getTempFileURL } from '../../utils/tcb';
7
+ import { getCloudInstance } from '../../utils/tcb';
8
8
  import { message, Button, Input, Modal, Progress, Upload, Text, } from 'tea-component';
9
9
  import { v4 as uuidv4 } from 'uuid';
10
10
  import { defaultBase64 } from './const';
11
11
  import { renderDecorator } from '../form/renderDecorator';
12
12
  import { usePlatform } from '../../utils/platform';
13
13
  import './index.css';
14
+ import styleM from './richtext.module.css';
14
15
  import { useSyncedRef } from '@react-hookz/web';
16
+ import { useTempUrl } from '../../utils/use-cloud-id-temp-url';
15
17
  // 默认图片类型
16
18
  const IMAGE_TYPES = [
17
19
  'image/jpeg',
@@ -21,6 +23,36 @@ const IMAGE_TYPES = [
21
23
  'image/tiff',
22
24
  'image/svg+xml',
23
25
  ];
26
+ const defaultControls = [
27
+ 'undo',
28
+ 'redo',
29
+ 'separator',
30
+ 'headings',
31
+ 'separator',
32
+ 'font-size',
33
+ 'separator',
34
+ 'line-height',
35
+ 'letter-spacing',
36
+ 'text-color',
37
+ 'bold',
38
+ 'italic',
39
+ 'underline',
40
+ 'strike-through',
41
+ 'superscript',
42
+ 'subscript',
43
+ 'remove-styles',
44
+ 'emoji',
45
+ 'text-indent',
46
+ 'text-align',
47
+ 'list-ul',
48
+ 'list-ol',
49
+ 'blockquote',
50
+ 'code',
51
+ 'link',
52
+ 'hr',
53
+ 'media',
54
+ 'clear',
55
+ ];
24
56
  export default function RichText({
25
57
  // 系统属性
26
58
  id, style, className, events,
@@ -37,37 +69,75 @@ label, labelVisible, value: initialValue, readOnly, layout, requiredFlag, onChan
37
69
  const isH5 = platform === 'h5';
38
70
  const subCls = classNames({
39
71
  'weui-cell': isH5,
40
- 'weui-cell_active': isH5,
72
+ // 'weui-cell_active': isH5,
41
73
  'weui-cell_form': isH5,
42
74
  'weui-cell_disabled': isH5 && disabled,
43
75
  });
76
+ const previousValueRef = useRef();
44
77
  const onDataChange = function (value) {
45
- events.change && events.change({ value: value === '<p></p>' ? '' : value });
46
- if (onChange) {
47
- if (value === '<p></p>') {
48
- onChange('');
49
- }
50
- else {
51
- onChange(value);
78
+ if (previousValueRef.current !== value) {
79
+ events.change &&
80
+ events.change({ value: value === '<p></p>' ? '' : value });
81
+ if (onChange) {
82
+ if (value === '<p></p>') {
83
+ onChange('');
84
+ }
85
+ else {
86
+ onChange(value);
87
+ }
52
88
  }
53
89
  }
90
+ previousValueRef.current = value;
54
91
  };
55
92
  useEffect(() => {
56
93
  const state = createStateFromContent(initialValue, {});
57
94
  setEditorState(state);
58
95
  }, []);
59
- const extendControls = useMemo(() => {
60
- return [
61
- {
62
- key: 'richtext-uploader',
63
- type: 'component',
64
- component: (React.createElement(CustomUploader, { acceptTypes: acceptTypes, maxSize: maxSize, cloudPath: cloudPath, onChange: (url) => {
65
- const state = ContentUtils.insertMedias(latestEditorState.current, [{ type: 'IMAGE', url }]);
66
- setEditorState(state);
67
- } })),
68
- },
96
+ const excludeControls = useMemo(() => {
97
+ const result = [
98
+ 'media',
99
+ 'fullscreen',
100
+ 'line-height',
101
+ 'letter-spacing',
102
+ 'emoji',
103
+ 'superscript',
104
+ 'subscript',
69
105
  ];
70
- }, [setEditorState, acceptTypes, maxSize, cloudPath, ContentUtils]);
106
+ if (isH5) {
107
+ result.push('separator', 'undo', 'redo', 'blockquote', 'code', 'link', 'hr', 'list-ul', 'list-ol', 'hr', 'clear', 'text-indent',
108
+ // 'font-size',
109
+ 'headings', 'remove-styles', 'text-align');
110
+ }
111
+ return result;
112
+ }, [isH5]);
113
+ const extendControls = useMemo(() => {
114
+ if (!isH5) {
115
+ return [
116
+ {
117
+ key: 'richtext-uploader',
118
+ type: 'component',
119
+ component: (React.createElement(CustomUploader, { acceptTypes: acceptTypes, maxSize: maxSize, cloudPath: cloudPath, onChange: (url) => {
120
+ const state = insertMedias(latestEditorState.current, [
121
+ { type: 'IMAGE', url },
122
+ ]);
123
+ setEditorState((curState) => {
124
+ const currentSelection = curState.getSelection();
125
+ EditorState.forceSelection(state, currentSelection);
126
+ return state;
127
+ });
128
+ } })),
129
+ },
130
+ ];
131
+ }
132
+ }, [
133
+ acceptTypes,
134
+ maxSize,
135
+ cloudPath,
136
+ latestEditorState,
137
+ insertMedias,
138
+ setEditorState,
139
+ isH5,
140
+ ]);
71
141
  // 修改img显示逻辑
72
142
  const blockRenderFn = (contentBlock, { editor, editorState }) => {
73
143
  var _a;
@@ -87,12 +157,8 @@ label, labelVisible, value: initialValue, readOnly, layout, requiredFlag, onChan
87
157
  }
88
158
  };
89
159
  const richTextEl = (React.createElement("div", { className: subCls },
90
- React.createElement("div", { style: {
91
- border: '1px solid #d1d1d1',
92
- backgroundColor: '#fff',
93
- ...style,
94
- } },
95
- React.createElement(Editor, { key: id, value: editorState, readOnly: readOnly, language: "zh", blockRendererFn: blockRenderFn, onBlur: (s) => {
160
+ React.createElement("div", { style: style, className: styleM.richtextInner },
161
+ React.createElement(Editor, { key: id, value: editorState, readOnly: readOnly, disabled: disabled, language: "zh", blockRendererFn: blockRenderFn, onBlur: (s) => {
96
162
  setEditorState(s);
97
163
  const html = convertEditorStateToHTML(s, {});
98
164
  onDataChange(html);
@@ -101,11 +167,10 @@ label, labelVisible, value: initialValue, readOnly, layout, requiredFlag, onChan
101
167
  content: '富文本长度过长,可能导致保存失败',
102
168
  });
103
169
  }
104
- }, excludeControls: ['media', 'fullscreen'],
170
+ }, controls: defaultControls, excludeControls: excludeControls,
105
171
  /** @ts-ignore jsx */
106
172
  extendControls: extendControls, handleKeyCommand: (command, editState) => {
107
- const newState = ContentUtils.handleKeyCommand(editState, command);
108
- console.log(newState, editState, command);
173
+ const newState = handleKeyCommand(editState, command);
109
174
  if (newState) {
110
175
  setEditorState(newState);
111
176
  return true;
@@ -158,10 +223,8 @@ export const CustomUploader = (props) => {
158
223
  };
159
224
  return (React.createElement(React.Fragment, null,
160
225
  React.createElement("button", { role: "richtext", type: "button", "data-title": "\u5A92\u4F53\u4E0A\u4F20", className: "control-item button", onClick: () => setState({ visible: true }) },
161
- React.createElement("svg", { viewBox: "64 64 896 896", focusable: "false", "data-icon": "file-image", width: "1em", height: "1em", fill: "currentColor", "aria-hidden": "true" },
162
- React.createElement("path", { d: "M534 352V136H232v752h560V394H576a42 42 0 01-42-42zm-134 50c22.1 0 40 17.9 40 40s-17.9 40-40 40-40-17.9-40-40 17.9-40 40-40zm296 294H328.1c-6.7 0-10.4-7.7-6.3-12.9l99.8-127.2a8 8 0 0112.6 0l41.1 52.4 77.8-99.2a8.1 8.1 0 0112.7 0l136.5 174c4.1 5.2.4 12.9-6.3 12.9z", fill: "#e6f7ff" }),
163
- React.createElement("path", { d: "M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM602 137.8L790.2 326H602V137.8zM792 888H232V136h302v216a42 42 0 0042 42h216v494z", fill: "#006eff" }),
164
- React.createElement("path", { d: "M553.1 509.1l-77.8 99.2-41.1-52.4a8 8 0 00-12.6 0l-99.8 127.2a7.98 7.98 0 006.3 12.9H696c6.7 0 10.4-7.7 6.3-12.9l-136.5-174a8.1 8.1 0 00-12.7 0zM360 442a40 40 0 1080 0 40 40 0 10-80 0z", fill: "#006eff" }))),
226
+ React.createElement("svg", { width: "17", height: "16", viewBox: "0 0 17 16", fill: "none", xmlns: "http://www.w3.org/2000/svg" },
227
+ React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M13.6205 1.61428V3.60631L15.6105 3.6063L15.6105 5.1063L13.6205 5.10631V7.08572H12.1205V5.10633L10.1391 5.10635L10.139 3.60635L12.1205 3.60633V1.61428H13.6205ZM8.84998 2.38572H2.49536C1.94308 2.38572 1.49536 2.83343 1.49536 3.38572V11.6761V13.3857C1.49536 13.403 1.4958 13.4201 1.49666 13.4372C1.5019 13.5405 1.52282 13.6397 1.5571 13.7324C1.69808 14.1138 2.06497 14.3857 2.49536 14.3857H4.49757H4.76178H12.4954C13.0476 14.3857 13.4954 13.938 13.4954 13.3857V13.2088L13.4954 13.2088V11.0909L13.4954 11.0909V8.38572H11.9954V9.59579L10.2484 7.85452L9.71895 7.32678L9.18948 7.85452L6.4372 10.5979L5.03662 9.20183L4.50715 8.67408L3.97769 9.20183L2.99536 10.181V3.88572H8.84998V2.38572ZM2.99536 12.8857V12.2988L4.50715 10.792L5.37481 11.6568L4.14188 12.8857H2.99536ZM11.9954 12.8857H6.26667L9.71895 9.44465L11.9954 11.7137V12.8857Z", fill: "#6A6F7B" }))),
165
228
  React.createElement(Modal, { onClose: () => {
166
229
  setState({ visible: false });
167
230
  }, visible: visible, maskClosable: true },
@@ -235,38 +298,28 @@ export const CustomUploader = (props) => {
235
298
  React.createElement(Text, { theme: "weak" }, "/\u62D6\u62FD\u5230\u6B64\u533A\u57DF")))))),
236
299
  uploading && (React.createElement(Progress, { style: { marginTop: '10px' }, percent: percent })))));
237
300
  };
301
+ const Img = React.memo(function Img(props) {
302
+ const { src, style, onError } = props;
303
+ const { data: realSrc, error } = useTempUrl(src);
304
+ const realstyle = useMemo(() => {
305
+ if (error) {
306
+ return { ...style, width: '80px' };
307
+ }
308
+ return style;
309
+ }, [error, style]);
310
+ return (React.createElement("img", { src: error ? defaultBase64 : realSrc, style: realstyle, onError: () => {
311
+ onError === null || onError === void 0 ? void 0 : onError();
312
+ } }));
313
+ });
314
+ const imgStyle = { maxWidth: '100%' };
238
315
  export const RichTextImg = ({ contentState, block }) => {
239
316
  const blockData = contentState.getEntity(block.getEntityAt(0)).getData();
240
317
  const { url } = blockData || {};
241
- const [src, setSrc] = React.useState('');
242
- const [width, setWidth] = React.useState('unset');
243
- useEffect(() => {
244
- const getSrc = async () => {
245
- try {
246
- if (url.includes('cloud://')) {
247
- const _src = await getTempFileURL(url);
248
- setSrc(_src || url);
249
- }
250
- else {
251
- setSrc(url);
252
- }
253
- }
254
- catch (e) {
255
- message.error({
256
- content: `显示图片失败:${e.message || '未知原因'}`,
257
- });
258
- }
259
- };
260
- getSrc();
261
- }, [url]);
262
- return (src && (React.createElement(React.Fragment, null,
318
+ return (url && (React.createElement(React.Fragment, null,
263
319
  React.createElement("div", { className: "bf-media" },
264
320
  React.createElement("div", { draggable: "true", className: "bf-image", style: { float: 'left' } },
265
321
  React.createElement("div", { style: { position: 'relative', display: 'inline-block' } },
266
- React.createElement("img", { src: src, style: { maxWidth: '100%', width }, onError: () => {
267
- setSrc(defaultBase64);
268
- setWidth('80px');
269
- } }),
322
+ React.createElement(Img, { src: url, style: imgStyle }),
270
323
  React.createElement("div", { className: "bf-pre-csize" }))),
271
324
  React.createElement("div", { style: {
272
325
  clear: 'both',
@@ -278,13 +331,14 @@ export const RichTextImg = ({ contentState, block }) => {
278
331
  RichText.defaultProps = {
279
332
  // 系统属性
280
333
  events: {},
281
- style: { width: '100%' },
334
+ style: {},
282
335
  // 组件属性
283
336
  label: '标题',
284
337
  labelVisible: true,
285
338
  name: 'formRichText',
286
339
  value: '',
287
- readOnly: false,
340
+ readOnly: true,
341
+ disabled: true,
288
342
  layout: 'vertical',
289
343
  requiredFlag: false,
290
344
  maxSize: 10,
@@ -0,0 +1,5 @@
1
+ .richtext_richtextInner__-9STf {
2
+ border: 0.07143rem solid #d1d1d1;
3
+ background-color: #fff;
4
+ width: 100%;
5
+ }
@@ -0,0 +1 @@
1
+ export declare function useTempUrl(cloudId: string): import("swr").SWRResponse<any, any>;
@@ -0,0 +1,13 @@
1
+ import useSWR from 'swr';
2
+ import { getTempFileURL } from './tcb';
3
+ export function useTempUrl(cloudId) {
4
+ const prefix = 'tcb:cloud-id:temp-url';
5
+ const key = `${prefix}:${cloudId}`;
6
+ return useSWR(key, async () => {
7
+ if (!cloudId.startsWith('cloud://')) {
8
+ return cloudId;
9
+ }
10
+ const tempUrl = await getTempFileURL(cloudId);
11
+ return tempUrl;
12
+ });
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/weda-ui",
3
- "version": "3.1.4",
3
+ "version": "3.1.6",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index",
6
6
  "miniprogram": "mpdist",
@@ -64,12 +64,13 @@
64
64
  "dayjs": "^1.10.7",
65
65
  "destr": "^1.1.1",
66
66
  "echarts": "^5.3.0",
67
- "kedao": "0.1.13",
67
+ "kedao": "^0.1.23",
68
68
  "lodash.isequal": "^4.5.0",
69
69
  "object.fromentries": "^2.0.5",
70
70
  "prop-types": "^15.7.2",
71
71
  "react-easy-swipe": "0.0.22",
72
72
  "spark-md5": "^3.0.2",
73
+ "swr": "^1.3.0",
73
74
  "tdesign-icons-react": "0.0.8",
74
75
  "tea-component": "^2.7.3",
75
76
  "uuid": "8.3.2",