@cloudbase/weda-ui 3.11.11 → 3.12.1

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 (47) hide show
  1. package/dist/configs/components/dataView.d.ts +1 -0
  2. package/dist/configs/components/dataView.js +2 -1
  3. package/dist/configs/components/listView.js +5 -12
  4. package/dist/configs/components/wd-form-arr.d.ts +4 -1
  5. package/dist/configs/components/wd-form-arr.js +11 -140
  6. package/dist/configs/components/wd-form-obj.d.ts +2 -0
  7. package/dist/configs/components/wd-form-obj.js +13 -1
  8. package/dist/configs/components/wd-modal.d.ts +10 -1
  9. package/dist/configs/components/wd-modal.js +52 -1
  10. package/dist/configs/components/wd-table.d.ts +10 -0
  11. package/dist/configs/components/wd-table.js +9 -17
  12. package/dist/configs/components/web-view.d.ts +4 -0
  13. package/dist/configs/components/web-view.js +19 -1
  14. package/dist/configs/index.d.ts +44 -4
  15. package/dist/configs/type-utils/type-form.d.ts +2 -0
  16. package/dist/configs/type-utils/type-form.js +5 -3
  17. package/dist/configs/utils/field.d.ts +4 -0
  18. package/dist/configs/utils/field.js +508 -0
  19. package/dist/style/index.css +41 -3
  20. package/dist/style/index.scss +1 -1
  21. package/dist/style/weda-ui.min.css +2 -2
  22. package/dist/web/components/form/uploader/uploader.pc.d.ts +8 -1
  23. package/dist/web/components/form/uploader/uploader.pc.js +22 -20
  24. package/dist/web/components/uploaderView/index.d.ts +8 -1
  25. package/dist/web/components/uploaderView/index.js +5 -4
  26. package/dist/web/components/wd-form-item/wd-form-item.js +3 -3
  27. package/dist/web/components/wd-form-item/wd-input-wrap.js +8 -2
  28. package/dist/web/components/wd-form-obj/base-form-obj.js +4 -1
  29. package/dist/web/components/wd-image/ImagePreview.d.ts +1 -0
  30. package/dist/web/components/wd-image/ImagePreview.js +124 -0
  31. package/dist/web/components/wd-image/image.d.ts +2 -1
  32. package/dist/web/components/wd-image/image.js +47 -159
  33. package/dist/web/components/wd-image/index.d.ts +1 -0
  34. package/dist/web/components/wd-image/index.js +7 -3
  35. package/dist/web/components/wd-menu-list/CommonMenuList.js +12 -1
  36. package/dist/web/components/wd-rich-text/wd-rich-text.js +1 -1
  37. package/dist/web/components/wd-select/relationSelect/relationSelect.js +7 -12
  38. package/dist/web/components/wd-select/select/selectUI.js +8 -13
  39. package/dist/web/components/wd-table/components/FieldRender/ImagePreview.js +8 -1
  40. package/dist/web/components/wd-table/components/FieldRender/index.js +2 -2
  41. package/dist/web/components/wd-table/wd-table.js +16 -46
  42. package/dist/web/components/wd-upload-file/wd-upload-file.js +1 -1
  43. package/dist/web/components/wd-upload-image/wd-upload-image.js +1 -1
  44. package/dist/web/components/web-view/web-view.d.ts +2 -0
  45. package/dist/web/components/web-view/web-view.js +2 -2
  46. package/dist/web/utils/getModelParams.js +8 -3
  47. package/package.json +3 -3
@@ -12,12 +12,15 @@ interface TempFileProps {
12
12
  export declare function UploaderPCInner(props: PropsType): JSX.Element;
13
13
  export interface TcbImageProps {
14
14
  fileID?: string;
15
+ allFile?: TempFileProps[];
15
16
  tempFile?: TempFileProps;
17
+ index?: number;
16
18
  isZoom?: boolean;
17
19
  onError?: (e: unknown) => void;
18
20
  imgTypeCls?: string;
19
- preivewIcon?: string;
21
+ previewIcon?: string;
20
22
  actions?: React.ReactNode;
23
+ portalContainer?: HTMLElement;
21
24
  }
22
25
  export declare const TcbImage: (props: TcbImageProps) => JSX.Element;
23
26
  export interface PropsType extends H5UploaderProps {
@@ -26,6 +29,10 @@ export interface PropsType extends H5UploaderProps {
26
29
  btnTitle?: string;
27
30
  uploadPath?: string;
28
31
  readOnly?: boolean;
32
+ popupContainer?: HTMLElement;
33
+ onChange?: (value: string | string[]) => void;
34
+ onError?: (error: Error) => void;
35
+ onSuccess?: (value: string | string[]) => void;
29
36
  }
30
37
  export declare function encodeConvert(src: any): any;
31
38
  export {};
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import * as React from 'react';
3
- import { Upload, Icon, ErrorTip, ImagePreview, ConfigProvider, } from 'tea-component';
3
+ import { Upload, Icon, ErrorTip, ConfigProvider } from 'tea-component';
4
4
  import { useTempUrl } from '../../../utils/hooks/use-cloud-id-temp-url';
5
5
  import { toBase64Uri } from '../../../utils/file2base64';
6
6
  import { isNil } from '../../../utils/lodash';
7
7
  import { errorHandler } from '../../../utils/error';
8
8
  import { WdIcon } from '../../wd-icon';
9
9
  import { useUploader } from './useUploadFile';
10
+ import { ImagePreview } from '../../wd-image/ImagePreview';
10
11
  // 默认组件类前缀
11
12
  export const CLASS_PREFIX = 'weda-uploader-pc';
12
13
  // 默认图片类型
@@ -20,7 +21,7 @@ export const IMAGE_TYPES = [
20
21
  'image/gif',
21
22
  ];
22
23
  export function UploaderPCInner(props) {
23
- const { tips = '', btnTitle = '上传图片', maxUploadCount = 9, maxSize = 10, acceptTypes = IMAGE_TYPES, events, single = false, disabled = false, onChange, imgTypeCls, readOnly, sourceType, callbacks, } = props;
24
+ const { tips = '', btnTitle = '上传图片', maxUploadCount = 9, maxSize = 10, acceptTypes = IMAGE_TYPES, events, single = false, disabled = false, onChange, imgTypeCls, readOnly, sourceType, callbacks, popupContainer: portalContainer, } = props;
24
25
  const { tempFile, uploading, upload, getTempFile } = useUploader(props);
25
26
  const handleChange = (allFile = [], isDelete = false) => {
26
27
  var _a;
@@ -83,8 +84,7 @@ export function UploaderPCInner(props) {
83
84
  if (typeof ret === 'boolean') {
84
85
  shouldUploadToCos = ret;
85
86
  }
86
- else if (Array.isArray(ret) &&
87
- ret.every((item) => item instanceof File)) {
87
+ else if (Array.isArray(ret) && ret.every((item) => item instanceof File)) {
88
88
  fileList = ret;
89
89
  }
90
90
  else if (!isNil(ret)) {
@@ -114,13 +114,11 @@ export function UploaderPCInner(props) {
114
114
  const extraProps = {};
115
115
  //是否支持多选
116
116
  extraProps['multiple'] = !single;
117
- extraProps['accept'] =
118
- acceptTypes.length === 0 ? IMAGE_TYPES : Array.from(new Set(acceptTypes));
117
+ extraProps['accept'] = acceptTypes.length === 0 ? IMAGE_TYPES : Array.from(new Set(acceptTypes));
119
118
  tips && (extraProps['title'] = tips);
120
119
  maxSize && (extraProps['maxSize'] = maxSize * 1024 * 1024);
121
120
  const hasActions = !uploading && !readOnly && !(disabled || sourceType === 'camera');
122
- return (_jsx(ConfigProvider, { classPrefix: "wedatea2td", children: _jsxs("div", { className: "_weda-fn-upload-result", children: [tempFile === null || tempFile === void 0 ? void 0 : tempFile.map((d) => (_jsx("div", { className: `_weda-fn-upload-result__item ${imgTypeCls}`, children: _jsx(TcbImage, { tempFile: d, imgTypeCls: imgTypeCls, isZoom: true, preivewIcon: "td:browse", actions: hasActions && (_jsx(WdIcon, { className: `${CLASS_PREFIX}__image-actions-delete`, name: "td:delete", onClick: () => deleteHandle(d), size: "sm" })) }) }, d.key))), _jsxs("div", { className: `${CLASS_PREFIX}__input-box`, children: [readOnly && tempFile.length < 1 && _jsx("div", { children: "-" }), sourceType === 'camera' || (disabled && !readOnly) ? (_jsx("li", { className: `_weda-fn-upload-result__item wedatea2td-disabled ${imgTypeCls}`, children: _jsxs("div", { className: "_weda-fn-upload-result__status", children: [_jsx("i", { className: "wedatea2td-icon wedatea2td-icon-plus", role: "img", "aria-label": "plus" }), _jsx("span", { className: "wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset", children: btnTitle })] }) })) : (((!single && tempFile.length < maxUploadCount) ||
123
- (single && tempFile.length < 1 && !uploading)) &&
121
+ return (_jsx(ConfigProvider, { classPrefix: "wedatea2td", children: _jsxs("div", { className: "_weda-fn-upload-result", children: [tempFile === null || tempFile === void 0 ? void 0 : tempFile.map((d, index) => (_jsx("div", { className: `_weda-fn-upload-result__item ${imgTypeCls}`, children: _jsx(TcbImage, { index: index, allFile: tempFile, tempFile: d, imgTypeCls: imgTypeCls, isZoom: true, previewIcon: "td:browse", portalContainer: portalContainer, actions: hasActions && (_jsx(WdIcon, { className: `${CLASS_PREFIX}__image-actions-delete`, name: "td:delete", onClick: () => deleteHandle(d), size: "sm" })) }) }, d.key))), _jsxs("div", { className: `${CLASS_PREFIX}__input-box`, children: [readOnly && tempFile.length < 1 && _jsx("div", { children: "-" }), sourceType === 'camera' || (disabled && !readOnly) ? (_jsx("li", { className: `_weda-fn-upload-result__item wedatea2td-disabled ${imgTypeCls}`, children: _jsxs("div", { className: "_weda-fn-upload-result__status", children: [_jsx("i", { className: "wedatea2td-icon wedatea2td-icon-plus", role: "img", "aria-label": "plus" }), _jsx("span", { className: "wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset", children: btnTitle })] }) })) : (((!single && tempFile.length < maxUploadCount) || (single && tempFile.length < 1 && !uploading)) &&
124
122
  !readOnly && (
125
123
  // single 模式时,当数组为空且不在上传文件过程中时显示
126
124
  _jsx(Upload, { ...extraProps, beforeUpload: beforeHandle, children: _jsxs("li", {
@@ -132,13 +130,13 @@ export function UploaderPCInner(props) {
132
130
  className: `_weda-fn-upload-result__item _weda-fn-upload-result__item--upload ${imgTypeCls}`, children: [imgTypeCls, _jsxs("div", { className: "_weda-fn-upload-result__status", children: [_jsx("i", { className: "wedatea2td-icon wedatea2td-icon-plus", role: "img", "aria-label": "plus" }), _jsx("span", { className: "wedatea2td-mt-1n wedatea2td-text-label wedatea2td-fz-reset", children: btnTitle })] })] }) })))] })] }) }));
133
131
  }
134
132
  export const TcbImage = (props) => {
135
- const { fileID, tempFile = { progress: 100, loading: false, realUrl: null, tempUrl: null }, isZoom, imgTypeCls, preivewIcon, actions, ...rest } = props;
133
+ const { fileID, tempFile = { progress: 100, loading: false, realUrl: null, tempUrl: null }, isZoom, imgTypeCls, previewIcon, actions, allFile = [], index, portalContainer, ...rest } = props;
136
134
  const { progress, loading, realUrl, tempUrl } = tempFile;
137
135
  const fileCloudID = (realUrl !== null && realUrl !== void 0 ? realUrl : tempUrl) || fileID;
138
136
  const [isError, setIsError] = React.useState(false);
139
137
  const { data: src, error: requestError } = useTempUrl(fileCloudID);
140
138
  const encodeSrc = encodeConvert(src);
141
- const renderImg = () => {
139
+ const renderImg = (open) => {
142
140
  if (isError || requestError)
143
141
  return _jsx(ErrorTip, {});
144
142
  if (!src)
@@ -146,28 +144,32 @@ export const TcbImage = (props) => {
146
144
  return (_jsxs(_Fragment, { children: [_jsx("img", { "data-testid": "uploaderpc_imgStyle", className: `${CLASS_PREFIX}__image ${imgTypeCls}`, ...rest, src: encodeURI(encodeSrc), onError: (e) => {
147
145
  setIsError(true);
148
146
  (props === null || props === void 0 ? void 0 : props.onError) && props.onError(e);
147
+ }, onClick: () => {
148
+ if (open) {
149
+ open();
150
+ }
149
151
  } }), loading && (_jsxs("div", { className: "_weda-fn-upload-result__status loading_bac", children: [_jsx(Icon, { type: "loading" }), _jsxs("div", { className: "wedatea2td-mt-1n wedatea2td-fz-reset", children: [progress, "%"] })] }))] }));
150
152
  };
151
153
  if (!isZoom)
152
154
  return renderImg();
155
+ const previewImageList = allFile.map((i) => i.realUrl || i.tempUrl);
153
156
  const previewProps = {
154
- key: fileCloudID,
157
+ index,
155
158
  'data-testid': 'uploaderpc_imgStyle',
156
159
  className: `${CLASS_PREFIX}__image ${imgTypeCls}`,
157
- ...rest,
158
- previewSrc: encodeURI(encodeSrc),
159
- onError: (e) => {
160
- setIsError(true);
161
- (props === null || props === void 0 ? void 0 : props.onError) && props.onError(e);
162
- },
160
+ src: encodeURI(encodeSrc),
161
+ previewImageList,
162
+ portalContainer,
163
163
  };
164
- if (preivewIcon || actions) {
164
+ if (previewIcon || actions) {
165
165
  return (_jsx(ImagePreview, { ...previewProps, children: (open) => {
166
- return (_jsxs(_Fragment, { children: [renderImg(), _jsxs("div", { className: `_weda-fn-upload-result__op ${imgTypeCls} ${CLASS_PREFIX}__image-actions`, children: [preivewIcon && (_jsx(WdIcon, { name: preivewIcon, onClick: open, className: `${CLASS_PREFIX}__image-actions-open`, size: "sm" })), actions && (_jsxs("span", { className: `${CLASS_PREFIX}__image-actions-separator`, children: [' ', "|", ' '] })), actions] })] }));
166
+ return (_jsxs(_Fragment, { children: [renderImg(), _jsxs("div", { className: `_weda-fn-upload-result__op ${imgTypeCls} ${CLASS_PREFIX}__image-actions`, children: [previewIcon && (_jsx(WdIcon, { name: previewIcon, onClick: open, className: `${CLASS_PREFIX}__image-actions-open`, size: "sm" })), actions && _jsx("span", { className: `${CLASS_PREFIX}__image-actions-separator`, children: "|" }), actions] })] }));
167
167
  } }));
168
168
  }
169
169
  else {
170
- return _jsx(ImagePreview, { ...previewProps, src: encodeURI(encodeSrc) });
170
+ return (_jsx(ImagePreview, { ...previewProps, children: (open) => {
171
+ return renderImg(open);
172
+ } }));
171
173
  }
172
174
  };
173
175
  //兼容私有化下载链接encodeURIComponent被编码情况
@@ -5,7 +5,7 @@ import './style';
5
5
  * 图片上传-展示组件
6
6
  */
7
7
  export default function UploaderView({ srcList, // 兼容 cloud:和https: 协议,兼容 字符串和字符串数组
8
- alt, gutter, height, width, events, isZoom, isEmptyPlace, className, id, style, }: PropsType): JSX.Element;
8
+ alt, gutter, height, width, events, isZoom, isEmptyPlace, className, id, style, popupContainer: portalContainer, }: PropsType): JSX.Element;
9
9
  export interface PropsType extends CommonPropsType {
10
10
  srcList?: string[] | string;
11
11
  alt?: string;
@@ -14,4 +14,11 @@ export interface PropsType extends CommonPropsType {
14
14
  height?: number;
15
15
  width?: number;
16
16
  isEmptyPlace?: boolean;
17
+ popupContainer?: HTMLElement;
18
+ events?: {
19
+ load?: ({ success, error }: {
20
+ success: string[];
21
+ error: string[];
22
+ }) => void;
23
+ };
17
24
  }
@@ -9,7 +9,7 @@ const CLASS_PREFIX = 'g-uploader-view';
9
9
  * 图片上传-展示组件
10
10
  */
11
11
  export default function UploaderView({ srcList, // 兼容 cloud:和https: 协议,兼容 字符串和字符串数组
12
- alt = '[加载失败]', gutter = 8, height = 100, width = 100, events = emptyObject, isZoom = true, isEmptyPlace = true, className, id, style, }) {
12
+ alt = '[加载失败]', gutter = 8, height = 100, width = 100, events = emptyObject, isZoom = true, isEmptyPlace = true, className, id, style, popupContainer: portalContainer, }) {
13
13
  const cls = classNames({
14
14
  [CLASS_PREFIX]: true,
15
15
  [className]: className,
@@ -26,10 +26,9 @@ alt = '[加载失败]', gutter = 8, height = 100, width = 100, events = emptyObj
26
26
  marginBottom: gutter,
27
27
  height: height,
28
28
  width: width,
29
+ cursor: isZoom ? 'zoom-in' : 'auto',
29
30
  };
30
- const values = []
31
- .concat(srcList)
32
- .filter((d) => typeof d === 'string' && d !== '');
31
+ const values = [].concat(srcList).filter((d) => typeof d === 'string' && d !== '');
33
32
  return (_jsx("div", { className: cls, id: id, style: style, children: _jsxs("div", { className: `${CLASS_PREFIX}__image-list`, children: [values.map((d, i) => {
34
33
  const imgProps = {
35
34
  fileID: d,
@@ -38,6 +37,8 @@ alt = '[加载失败]', gutter = 8, height = 100, width = 100, events = emptyObj
38
37
  isZoom,
39
38
  onLoad: () => setSuccessList((list) => [...list, d]),
40
39
  onError: () => setErrorList((list) => [...list, d]),
40
+ portalContainer,
41
+ allFile: values === null || values === void 0 ? void 0 : values.map((d) => ({ realUrl: d })),
41
42
  };
42
43
  return (_jsx("div", { className: `${CLASS_PREFIX}__image-box`, style: boxStyle, title: d, children: _jsx(TcbImage, { ...imgProps }) }, `${d}-${i}`));
43
44
  }), values.length === 0 && isEmptyPlace && (_jsx("div", { className: `${CLASS_PREFIX}__image-box`, style: boxStyle, children: _jsx("img", { className: `${CLASS_PREFIX}__image`, alt: "\u6682\u65E0\u56FE\u7247" }) }))] }) }));
@@ -66,9 +66,9 @@ export function WdFormItem(props) {
66
66
  const Message = validateErrorMsg && (_jsx("p", { className: `${item}__help`, children: _jsx("span", { className: `${classPrefix}-g-text-${validateState} ${root}__error`, children: textToString(validateErrorMsg) }) }));
67
67
  if (!visible)
68
68
  return null;
69
- return (_jsxs("div", { className: cls, id: isRoot ? id : null, style: style, children: [_jsx("div", { className: itemWrap, children: LabelContainer ? (_jsx(LabelContainerComp, { LabelContainer: LabelContainer, isRoot: isRoot, isH5: isH5, Label: Label, Item: Item })) : (_jsxs(_Fragment, { children: [Label, Item] })) }), Message, Help] }));
69
+ return (_jsxs("div", { className: cls, id: isRoot ? id : null, style: style, children: [_jsx("div", { className: itemWrap, children: LabelContainer ? (_jsx(LabelContainerComp, { LabelContainer: LabelContainer, isRoot: isRoot, isH5: isH5, Label: Label, Item: Item, mode: props === null || props === void 0 ? void 0 : props.mode })) : (_jsxs(_Fragment, { children: [Label, Item] })) }), Message, Help] }));
70
70
  }
71
- const LabelContainerComp = ({ isRoot, isH5, Label, Item, LabelContainer }) => {
71
+ const LabelContainerComp = ({ isRoot, isH5, Label, Item, LabelContainer, mode, }) => {
72
72
  const showLabel = isRoot && !isH5;
73
- return (_jsxs(_Fragment, { children: [showLabel && Label, _jsx(LabelContainer, { isRoot: isRoot, Label: Label, Item: Item })] }));
73
+ return (_jsxs(_Fragment, { children: [showLabel && Label, _jsx(LabelContainer, { isRoot: isRoot, Label: Label, Item: Item, mode: mode })] }));
74
74
  };
@@ -1,5 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef, useMemo } from 'react';
2
+ import { useRef, useMemo, useState } from 'react';
3
3
  import { useConfig } from '../../utils/config-context';
4
4
  import classNames from '../../utils/classnames';
5
5
  import { useSize, convertIconSize } from '../../utils/hooks/useFormLegacy';
@@ -16,6 +16,7 @@ export const WdInputWrap = (props) => {
16
16
  const { classPrefix } = useConfig();
17
17
  const size = useSize(props);
18
18
  const iconSize = convertIconSize(size);
19
+ const [isFocus, setIsFocus] = useState(false);
19
20
  const root = `${classPrefix}-${classRoot}`;
20
21
  const inputWrap = `${classPrefix}-form-input-wrap`;
21
22
  const contentCls = `${inputWrap}__content`;
@@ -29,11 +30,16 @@ export const WdInputWrap = (props) => {
29
30
  [`${inputWrap}--no-radius-left`]: before,
30
31
  [`${inputWrap}--no-radius-right`]: after,
31
32
  [`${inputWrap}--no-radius`]: before && after,
33
+ 'is-focused': isFocus,
32
34
  });
33
35
  const propsStartWithOn = useMemo(() => {
34
36
  return filterPropsWithOn(rest);
35
37
  }, [rest]);
36
38
  if (readOnly)
37
39
  return _jsx(_Fragment, { children: children });
38
- return (_jsxs("div", { className: cls, ref: wrapRef, onFocus: () => { var _a, _b; return (_b = (_a = wrapRef.current) === null || _a === void 0 ? void 0 : _a.classList) === null || _b === void 0 ? void 0 : _b.add('is-focused'); }, onBlur: () => { var _a, _b; return (_b = (_a = wrapRef.current) === null || _a === void 0 ? void 0 : _a.classList) === null || _b === void 0 ? void 0 : _b.remove('is-focused'); }, ...propsStartWithOn, children: [prefixType && (_jsx("div", { className: prefixCls, children: _jsx(WdIcon, { size: iconSize, name: prefixIcon, type: prefixType, src: prefixSrc, className: prefixIconCls }) })), _jsx("div", { className: contentCls, children: children }), hasClearIcon && (_jsx("div", { className: suffixCls, children: _jsx(WdIcon, { size: iconSize, className: `${classPrefix}-icon__trigger`, name: "td:close-circle-filled", onMouseDown: onClear }) })), !hasClearIcon && suffixType && (_jsx("div", { className: suffixCls, children: _jsx(WdIcon, { size: iconSize, name: suffixIcon, type: suffixType, src: suffixSrc, className: suffixIconCls }) }))] }));
40
+ return (_jsxs("div", { className: cls, ref: wrapRef, onFocus: () => {
41
+ setIsFocus(true);
42
+ }, onBlur: () => {
43
+ setIsFocus(false);
44
+ }, ...propsStartWithOn, children: [prefixType && (_jsx("div", { className: prefixCls, children: _jsx(WdIcon, { size: iconSize, name: prefixIcon, type: prefixType, src: prefixSrc, className: prefixIconCls }) })), _jsx("div", { className: contentCls, children: children }), hasClearIcon && (_jsx("div", { className: suffixCls, children: _jsx(WdIcon, { size: iconSize, className: `${classPrefix}-icon__trigger`, name: "td:close-circle-filled", onMouseDown: onClear }) })), !hasClearIcon && suffixType && (_jsx("div", { className: suffixCls, children: _jsx(WdIcon, { size: iconSize, name: suffixIcon, type: suffixType, src: suffixSrc, className: suffixIconCls }) }))] }));
39
45
  };
@@ -27,7 +27,7 @@ const classRoot = 'form-obj';
27
27
  */
28
28
  const getValueName = (operateName, currentName) => operateName.replace(new RegExp(`^${currentName}(\\.)?`), '');
29
29
  const LabelContainer = (props) => {
30
- const { Label, Item } = props || {};
30
+ const { Label, Item, mode } = props || {};
31
31
  const cardRef = React.createRef();
32
32
  const [iconName, setIconName] = useState('chevronup');
33
33
  const headerSlot = (_jsxs(_Fragment, { children: [_jsx(WdIcon, { name: iconName, events: {
@@ -35,6 +35,9 @@ const LabelContainer = (props) => {
35
35
  setIconName(iconName === 'chevrondown' ? 'chevronup' : 'chevrondown');
36
36
  },
37
37
  } }), Label] }));
38
+ if (mode === 'custom' || mode === 'table') {
39
+ return _jsx(_Fragment, { children: Item });
40
+ }
38
41
  return (_jsx(WdCard, { ref: cardRef, className: iconName === 'chevrondown' ? 'wd-card-content__hidden' : '', showContent: true, headerSlot: headerSlot, contentSlot: Item, events: { tap: () => { } } }));
39
42
  };
40
43
  export const BaseFormObj = forwardRef(function BaseFormObj(props, ref) {
@@ -0,0 +1 @@
1
+ export declare const ImagePreview: (props: any) => JSX.Element;
@@ -0,0 +1,124 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable @typescript-eslint/no-magic-numbers */
3
+ import React, { useState, useMemo } from 'react';
4
+ import { useGesture } from '@use-gesture/react';
5
+ import { Portal } from '../common/portal';
6
+ import { useConfig } from '../../utils/config-context';
7
+ import { usePlatform } from '../../utils/platform';
8
+ import { useSyncValue } from '../../utils/hooks/useSyncValue';
9
+ import isObjectEqual from '../../utils/isObjectEqual';
10
+ import { useTempUrl } from '../../utils/hooks/use-cloud-id-temp-url';
11
+ import { WdIcon } from '../wd-icon';
12
+ const ASPECT_RATIO = 1;
13
+ export const ImagePreview = (props) => {
14
+ const { portalContainer, isStopPropagation = false, maskClosable = false, src, style = {}, children, previewImageList = [], index = 0, } = props;
15
+ // cloud 或者 https
16
+ const [currentImg, setCurrentImg] = useSyncValue(previewImageList[index], isObjectEqual);
17
+ const [visible, setVisible] = useState(false);
18
+ const platform = usePlatform();
19
+ const [translateX, setTranslateX] = React.useState(0);
20
+ const [translateY, setTranslateY] = React.useState(0);
21
+ const [previewScale, setPreviewScale] = React.useState(ASPECT_RATIO);
22
+ const [rotate, setRotate] = React.useState(0);
23
+ const { data: realSrc } = useTempUrl(currentImg);
24
+ const previewStyle = platform === 'h5'
25
+ ? {
26
+ touchAction: 'none',
27
+ backgroundImage: `url('${realSrc || src}')`,
28
+ transform: `translate(${translateX}px, ${translateY}px) scale(${previewScale})`,
29
+ ...style,
30
+ }
31
+ : {
32
+ touchAction: 'none',
33
+ backgroundImage: `url('${realSrc || src}')`,
34
+ transform: `rotate(${rotate}deg)`,
35
+ ...style,
36
+ };
37
+ const { classPrefix } = useConfig();
38
+ React.useEffect(() => {
39
+ // 防止触发浏览器的放大缩小
40
+ const handler = (e) => e.preventDefault();
41
+ document.addEventListener('gesturestart', handler);
42
+ document.addEventListener('gesturechange', handler);
43
+ return () => {
44
+ document.removeEventListener('gesturestart', handler);
45
+ document.removeEventListener('gesturechange', handler);
46
+ };
47
+ }, []);
48
+ const onMaskClick = (e) => {
49
+ if (isStopPropagation) {
50
+ e.stopPropagation();
51
+ }
52
+ if (maskClosable) {
53
+ setVisible(false);
54
+ }
55
+ };
56
+ const bind = useGesture({
57
+ onClick: ({ event }) => {
58
+ // 防止冒泡出发关闭预览
59
+ event.stopPropagation();
60
+ if (maskClosable) {
61
+ setVisible(false);
62
+ }
63
+ },
64
+ onPinch: ({ offset }) => {
65
+ const [s] = offset;
66
+ setPreviewScale(s);
67
+ },
68
+ onDrag: ({ offset, event }) => {
69
+ event.stopPropagation();
70
+ const [x, y] = offset;
71
+ setTranslateX(x);
72
+ setTranslateY(y);
73
+ },
74
+ }, {
75
+ drag: {
76
+ delay: true,
77
+ preventDefault: true,
78
+ from: () => [translateX, translateY],
79
+ },
80
+ pinch: {
81
+ scaleBounds: { min: 0.6, max: 5 },
82
+ pointer: {
83
+ touch: true,
84
+ },
85
+ },
86
+ });
87
+ const child = useMemo(() => {
88
+ return children(() => {
89
+ setVisible(true);
90
+ // 重置
91
+ setPreviewScale(ASPECT_RATIO);
92
+ setRotate(0);
93
+ setTranslateX(0);
94
+ setTranslateY(0);
95
+ setCurrentImg(previewImageList[index]);
96
+ });
97
+ }, [children, index, previewImageList, setCurrentImg]);
98
+ return (_jsxs(_Fragment, { children: [child, visible && (_jsx(Portal, { type: "div", portalContainer: portalContainer, children: _jsx("div", { "data-testid": "portal-container", style: { zIndex: 1001, position: 'relative' }, className: `${classPrefix}-image-preview-container`, children: _jsxs("div", { className: `${classPrefix}-image-mask`, onClick: onMaskClick, children: [_jsx("div", { onClick: (e) => {
99
+ if (isStopPropagation) {
100
+ e.stopPropagation();
101
+ }
102
+ setVisible(false);
103
+ }, className: `${classPrefix}-image-mask__close-btn`, children: _jsx("i", { className: `${classPrefix}-image-mask__icon-close` }) }), _jsx("div", { ...bind(), className: `${classPrefix}-image-preview`, style: previewStyle }), platform === 'pc' && (_jsxs("div", { className: `${classPrefix}-image-preview-toolbar`, children: [(previewImageList === null || previewImageList === void 0 ? void 0 : previewImageList.length) > 1 && (_jsxs(_Fragment, { children: [_jsx("span", { className: "wd-icon-wrap wd-event-tap", children: _jsx(WdIcon, { name: 'td:chevron-left', size: "sm", events: {
104
+ tap: () => {
105
+ const index = previewImageList.findIndex((i) => i === currentImg);
106
+ const currentIndex = index === 0 ? previewImageList.length - 1 : index - 1;
107
+ setCurrentImg(previewImageList[currentIndex]);
108
+ setRotate(0);
109
+ },
110
+ } }) }), _jsx("span", { className: "wd-icon-wrap wd-event-tap", children: _jsx(WdIcon, { name: 'td:chevron-right', size: "sm", events: {
111
+ tap: () => {
112
+ const index = previewImageList.findIndex((i) => i === currentImg);
113
+ const currentIndex = index === previewImageList.length - 1 ? 0 : index + 1;
114
+ setCurrentImg(previewImageList[currentIndex]);
115
+ setRotate(0);
116
+ },
117
+ } }) })] })), _jsx("span", { className: "wd-icon-wrap wd-event-tap", children: _jsx(WdIcon, { name: 'td:anticlockwise', size: "sm", events: {
118
+ tap: (arg, { originEvent: e }) => {
119
+ e.stopPropagation();
120
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
121
+ setRotate(rotate - 90);
122
+ },
123
+ } }) })] }))] }) }) }))] }));
124
+ };
@@ -5,6 +5,7 @@ interface ImageInnerPropsType extends Except<PropsType, 'fit'> {
5
5
  objectFit: React.CSSProperties['objectFit'];
6
6
  isError: boolean;
7
7
  setIsError: React.Dispatch<React.SetStateAction<boolean>>;
8
+ portalContainer?: HTMLElement;
8
9
  }
9
- export declare function ImageInner({ objectFit, style, className, alt, src, isError, setIsError, events, lazyLoad, maskClosable, imgPreview, id, isStopPropagation, }: ImageInnerPropsType): JSX.Element;
10
+ export declare function ImageInner({ objectFit, style, className, alt, src, isError, setIsError, events, lazyLoad, maskClosable, imgPreview, id, isStopPropagation, portalContainer, }: ImageInnerPropsType): JSX.Element;
10
11
  export {};
@@ -1,171 +1,59 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import * as React from 'react';
3
3
  import { usePlatform } from '../../utils/platform';
4
- import { useGesture } from '@use-gesture/react';
5
- import { useConfig } from '../../utils/config-context';
6
- import { useRef } from 'react';
7
- import { Portal } from '../common/portal';
4
+ import { ImagePreview } from './ImagePreview';
8
5
  const ASPECT_RASIO = 1;
9
6
  const OFFSET_RASIO = 0.5;
10
- const SCALE_RASIO_PC = 0.8;
11
- const SCALE_RASIO_H5 = 1;
12
- export function ImageInner({ objectFit, style, className, alt, src, isError, setIsError, events, lazyLoad, maskClosable, imgPreview, id, isStopPropagation, }) {
13
- var _a;
14
- const { classPrefix } = useConfig();
7
+ const SCALE_RADIO_PC = 0.8;
8
+ const SCALE_RADIO_H5 = 1;
9
+ export function ImageInner(_a) {
10
+ var _b;
11
+ var { objectFit, style, className, alt, src, isError, setIsError, events, lazyLoad, maskClosable, imgPreview, id, isStopPropagation, portalContainer = (_b = document.getElementById('root')) !== null && _b !== void 0 ? _b : document.body, } = _a;
15
12
  const platform = usePlatform();
16
- const [imgShow, setImgShow] = React.useState(false);
17
- const onMaskClick = (e) => {
18
- if (isStopPropagation) {
19
- e.stopPropagation();
20
- }
21
- if (maskClosable) {
22
- setImgShow(false);
23
- }
24
- };
25
- const portalContainer = useRef((_a = document.getElementById('root')) !== null && _a !== void 0 ? _a : document.body);
26
13
  const [showHeight, setShowHeight] = React.useState(0);
27
14
  const [showWidth, setShowWidth] = React.useState(0);
28
15
  const realWidth = React.useRef(0);
29
16
  const realHeight = React.useRef(0);
30
17
  const [offsetHeight, setOffsetHeight] = React.useState(0);
31
18
  const [offsetWidth, setOffsetWidth] = React.useState(0);
32
- const [translateX, setTranslateX] = React.useState(0);
33
- const [translateY, setTranslateY] = React.useState(0);
34
- const [previewScale, setPreviewScale] = React.useState(ASPECT_RASIO);
35
- React.useEffect(() => {
36
- // 防止触发浏览器的放大缩小
37
- const handler = (e) => e.preventDefault();
38
- document.addEventListener('gesturestart', handler);
39
- document.addEventListener('gesturechange', handler);
40
- return () => {
41
- document.removeEventListener('gesturestart', handler);
42
- document.removeEventListener('gesturechange', handler);
43
- };
44
- }, []);
45
- const bind = useGesture({
46
- onClick: ({ event }) => {
47
- // 防止冒泡出发关闭预览
48
- event.stopPropagation();
49
- if (maskClosable) {
50
- setImgShow(false);
51
- }
52
- },
53
- onPinch: ({ offset }) => {
54
- const [s] = offset;
55
- setPreviewScale(s);
56
- },
57
- onDrag: ({ offset, event }) => {
58
- event.stopPropagation();
59
- const [x, y] = offset;
60
- setTranslateX(x);
61
- setTranslateY(y);
62
- },
63
- }, {
64
- drag: {
65
- delay: true,
66
- preventDefault: true,
67
- from: () => [translateX, translateY],
68
- },
69
- pinch: {
70
- scaleBounds: { min: 0.6, max: 5 },
71
- pointer: {
72
- touch: true,
73
- },
74
- },
75
- });
76
- if (platform === 'h5' || !imgPreview || isError) {
77
- return (_jsxs(_Fragment, { children: [_jsx("img", { "data-testid": "wd-image", id: id, style: {
78
- objectFit,
79
- ...style,
80
- }, className: `${className} wd-h5-image`, alt: alt, src: src, onLoad: (e) => {
81
- const img = e.target;
82
- const { naturalHeight, naturalWidth } = img;
83
- realHeight.current = naturalHeight;
84
- realWidth.current = naturalWidth;
85
- setIsError(false);
86
- events.load && events.load({}, { originEvent: e });
87
- }, onError: (e) => {
88
- setIsError(true);
89
- events.error && events.error({}, { originEvent: e });
90
- }, onClick: (e) => {
91
- if (isStopPropagation) {
92
- e.stopPropagation();
93
- }
94
- if (imgPreview && !isError) {
95
- setTranslateX(0);
96
- setTranslateY(0);
97
- setPreviewScale(ASPECT_RASIO);
98
- const windowHeight = window.innerHeight;
99
- const windowWidth = window.innerWidth;
100
- const widthRasio = (windowWidth * SCALE_RASIO_H5) / realWidth.current;
101
- const heightRasio = (windowHeight * SCALE_RASIO_H5) / realHeight.current;
102
- const scale = Math.min(widthRasio, heightRasio, ASPECT_RASIO) || ASPECT_RASIO;
103
- setOffsetHeight((windowHeight - realHeight.current * scale) * OFFSET_RASIO);
104
- setOffsetWidth((windowWidth - realWidth.current * scale) * OFFSET_RASIO);
105
- setShowHeight(realHeight.current * scale);
106
- setShowWidth(realWidth.current * scale);
107
- setImgShow(true);
108
- }
109
- events.tap && events.tap({}, { originEvent: e });
110
- }, loading: lazyLoad ? 'lazy' : undefined }), imgShow && (_jsx(Portal, { type: "div", portalContainer: portalContainer, children: _jsx("div", { "data-testid": "portal-container", style: { zIndex: 1001, position: 'relative' }, className: `${classPrefix}-image-preview-container`, children: _jsxs("div", { className: `${classPrefix}-image-mask`, onClick: onMaskClick, children: [_jsx("div", { onClick: (e) => {
111
- if (isStopPropagation) {
112
- e.stopPropagation();
113
- }
114
- setImgShow(false);
115
- }, className: `${classPrefix}-image-mask__close-btn`, children: _jsx("i", { className: `${classPrefix}-image-mask__icon-close` }) }), _jsx("div", { ...bind(), className: `${classPrefix}-image-preview`, style: {
116
- touchAction: 'none',
117
- backgroundImage: `url('${src}')`,
118
- transform: `translate(${translateX}px, ${translateY}px) scale(${previewScale})`,
119
- width: showWidth,
120
- height: showHeight,
121
- marginTop: offsetHeight,
122
- marginLeft: offsetWidth,
123
- } })] }) }) }))] }));
124
- }
125
- else {
126
- return (_jsxs(_Fragment, { children: [_jsx("img", { "data-testid": "wd-image", id: id, style: {
127
- objectFit,
128
- cursor: 'zoom-in',
129
- ...style,
130
- }, className: `${className} wd-pc-image`, alt: alt, src: src, onLoad: (e) => {
131
- const img = e.target;
132
- const { naturalHeight, naturalWidth } = img;
133
- realHeight.current = naturalHeight;
134
- realWidth.current = naturalWidth;
135
- setIsError(false);
136
- events.load && events.load({}, { originEvent: e });
137
- }, onError: (e) => {
138
- setIsError(true);
139
- events.error && events.error({}, { originEvent: e });
140
- }, loading: lazyLoad ? 'lazy' : undefined, onClick: (e) => {
141
- if (isStopPropagation) {
142
- e.stopPropagation();
143
- }
144
- if (imgPreview && !isError) {
145
- const windowHeight = window.innerHeight;
146
- const windowWidth = window.innerWidth;
147
- const widthRasio = (windowWidth * SCALE_RASIO_PC) / realWidth.current;
148
- const heightRasio = (windowHeight * SCALE_RASIO_PC) / realHeight.current;
149
- const scale = Math.min(widthRasio, heightRasio, ASPECT_RASIO) || ASPECT_RASIO;
150
- setOffsetHeight((windowHeight - realHeight.current * scale) * OFFSET_RASIO);
151
- setOffsetWidth((windowWidth - realWidth.current * scale) * OFFSET_RASIO);
152
- setShowHeight(realHeight.current * scale);
153
- setShowWidth(realWidth.current * scale);
154
- setImgShow(true);
155
- }
156
- events.tap && events.tap({}, { originEvent: e });
157
- } }), imgShow && (_jsx(Portal, { type: "div", portalContainer: portalContainer, children: _jsx("div", { "data-testid": "portal-container", style: { zIndex: 1001, position: 'relative' }, className: `${classPrefix}-image-preview-container`, children: _jsxs("div", { className: `${classPrefix}-image-mask`, onClick: onMaskClick, children: [_jsx("div", { onClick: (e) => {
158
- if (isStopPropagation) {
159
- e.stopPropagation();
160
- }
161
- setImgShow(false);
162
- }, className: `${classPrefix}-image-mask__close-btn`, children: _jsx("i", { className: `${classPrefix}-image-mask__icon-close` }) }), _jsx("div", { ...bind(), className: `${classPrefix}-image-preview`, style: {
163
- touchAction: 'none',
164
- backgroundImage: `url('${src}')`,
165
- width: showWidth,
166
- height: showHeight,
167
- marginTop: offsetHeight,
168
- marginLeft: offsetWidth,
169
- } })] }) }) }))] }));
170
- }
19
+ const SCALE_RADIO = platform === 'h5' ? SCALE_RADIO_H5 : SCALE_RADIO_PC;
20
+ const previewStyle = {
21
+ width: showWidth,
22
+ height: showHeight,
23
+ marginTop: offsetHeight,
24
+ marginLeft: offsetWidth,
25
+ };
26
+ return (_jsx(ImagePreview, { portalContainer: portalContainer, maskClosable: maskClosable, style: previewStyle, src: src, children: (open) => {
27
+ return (_jsx("img", { "data-testid": "wd-image", id: id, style: {
28
+ objectFit,
29
+ ...style,
30
+ }, className: `${className}`, alt: alt, src: src, onLoad: (e) => {
31
+ const img = e.target;
32
+ const { naturalHeight, naturalWidth } = img;
33
+ realHeight.current = naturalHeight;
34
+ realWidth.current = naturalWidth;
35
+ setIsError(false);
36
+ events.load && events.load({}, { originEvent: e });
37
+ }, onError: (e) => {
38
+ setIsError(true);
39
+ events.error && events.error({}, { originEvent: e });
40
+ }, onClick: (e) => {
41
+ if (isStopPropagation) {
42
+ e.stopPropagation();
43
+ }
44
+ events.tap && events.tap({}, { originEvent: e });
45
+ if (imgPreview && !isError) {
46
+ const windowHeight = window.innerHeight;
47
+ const windowWidth = window.innerWidth;
48
+ const widthRasio = (windowWidth * SCALE_RADIO) / realWidth.current;
49
+ const heightRasio = (windowHeight * SCALE_RADIO) / realHeight.current;
50
+ const scale = Math.min(widthRasio, heightRasio, ASPECT_RASIO) || ASPECT_RASIO;
51
+ setOffsetHeight((windowHeight - realHeight.current * scale) * OFFSET_RASIO);
52
+ setOffsetWidth((windowWidth - realWidth.current * scale) * OFFSET_RASIO);
53
+ setShowHeight(realHeight.current * scale);
54
+ setShowWidth(realWidth.current * scale);
55
+ open();
56
+ }
57
+ }, loading: lazyLoad ? 'lazy' : undefined }));
58
+ } }));
171
59
  }
@@ -3,6 +3,7 @@ import type { CommonPropsType } from '../../types';
3
3
  import type { DataType } from '../../../configs/components/image';
4
4
  export interface PropsType extends CommonPropsType, DataType {
5
5
  isStopPropagation?: boolean;
6
+ popupContainer?: HTMLElement;
6
7
  }
7
8
  import '../style';
8
9
  declare const _default: React.ForwardRefExoticComponent<PropsType & React.RefAttributes<unknown>>;