@hi-ui/schema-fields 4.0.0-experimental.7 → 4.0.0-experimental.9

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 (82) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/base.d.ts +44 -0
  3. package/lib/bundle.d.ts +76 -0
  4. package/lib/bundle.js +66 -0
  5. package/lib/components/async-refill-placeholder/index.d.ts +7 -0
  6. package/lib/components/image-preview/index.d.ts +5 -0
  7. package/lib/components/image-preview/index.js +49 -0
  8. package/lib/components/span/index.d.ts +8 -0
  9. package/lib/components/upload-bridge/index.d.ts +5 -0
  10. package/lib/components/upload-bridge/index.js +214 -0
  11. package/lib/components/upload-bridge/type.d.ts +26 -0
  12. package/lib/components/upload-bridge/utils.d.ts +11 -0
  13. package/lib/components/upload-bridge/utils.js +66 -0
  14. package/lib/ctx.d.ts +26 -0
  15. package/lib/editable/ctx.d.ts +5 -0
  16. package/lib/editable/editable.d.ts +18 -0
  17. package/lib/editable/index.d.ts +14 -0
  18. package/lib/editable/readonly.d.ts +8 -0
  19. package/lib/editable/simple.d.ts +8 -0
  20. package/lib/editable/type.d.ts +9 -0
  21. package/lib/editable/use-readonly.d.ts +26 -0
  22. package/lib/extensible/selectable/index.d.ts +31 -0
  23. package/lib/extensible/selectable/index.js +101 -0
  24. package/lib/extensible/selectable/match-cascader.d.ts +19 -0
  25. package/lib/extensible/selectable/match-cascader.js +179 -0
  26. package/lib/extensible/selectable/type.d.ts +16 -0
  27. package/lib/fields/basic/cascader/index.d.ts +10 -0
  28. package/lib/fields/basic/cascader/index.js +83 -0
  29. package/lib/fields/basic/check-cascader/index.d.ts +11 -0
  30. package/lib/fields/basic/check-cascader/index.js +44 -0
  31. package/lib/fields/basic/check-select/index.d.ts +34 -0
  32. package/lib/fields/basic/check-select/index.js +75 -0
  33. package/lib/fields/basic/check-tree-select/index.d.ts +10 -0
  34. package/lib/fields/basic/check-tree-select/index.js +47 -0
  35. package/lib/fields/basic/checkbox/index.d.ts +19 -0
  36. package/lib/fields/basic/checkbox/index.js +70 -0
  37. package/lib/fields/basic/counter/index.d.ts +7 -0
  38. package/lib/fields/basic/counter/index.js +26 -0
  39. package/lib/fields/basic/radio/index.d.ts +7 -0
  40. package/lib/fields/basic/radio/index.js +30 -0
  41. package/lib/fields/basic/rating/index.d.ts +7 -0
  42. package/lib/fields/basic/rating/index.js +26 -0
  43. package/lib/fields/basic/select/index.d.ts +12 -0
  44. package/lib/fields/basic/select/index.js +83 -0
  45. package/lib/fields/basic/slider/index.d.ts +7 -0
  46. package/lib/fields/basic/slider/index.js +26 -0
  47. package/lib/fields/basic/switch/index.d.ts +7 -0
  48. package/lib/fields/basic/switch/index.js +33 -0
  49. package/lib/fields/basic/textarea/index.d.ts +7 -0
  50. package/lib/fields/basic/textarea/index.js +26 -0
  51. package/lib/fields/basic/time-picker/index.d.ts +8 -0
  52. package/lib/fields/basic/time-picker/index.js +31 -0
  53. package/lib/fields/basic/time-picker/index.scss.js +13 -0
  54. package/lib/fields/basic/tree-select/index.d.ts +11 -0
  55. package/lib/fields/basic/tree-select/index.js +47 -0
  56. package/lib/fields/basic/upload/custom.d.ts +3 -0
  57. package/lib/fields/basic/upload/custom.js +16 -0
  58. package/lib/fields/basic/upload/index.d.ts +8 -0
  59. package/lib/fields/basic/upload/index.js +34 -0
  60. package/lib/fields/enhance/number-range/index.d.ts +7 -0
  61. package/lib/fields/enhance/number-range/index.js +26 -0
  62. package/lib/fields/semantic/date/index.d.ts +15 -0
  63. package/lib/fields/semantic/date/index.js +67 -0
  64. package/lib/fields/semantic/image/index.d.ts +11 -0
  65. package/lib/fields/semantic/image/index.js +51 -0
  66. package/lib/fields/semantic/image/upload.d.ts +3 -0
  67. package/lib/fields/semantic/image/upload.js +20 -0
  68. package/lib/fields/semantic/link/index.d.ts +31 -0
  69. package/lib/fields/semantic/link/index.js +82 -0
  70. package/lib/fields/semantic/number/index.d.ts +21 -0
  71. package/lib/fields/semantic/number/index.js +91 -0
  72. package/lib/fields/semantic/tag/index.d.ts +25 -0
  73. package/lib/fields/semantic/tag/index.js +100 -0
  74. package/lib/fields/semantic/tag/index.scss.js +13 -0
  75. package/lib/fields/semantic/tag/preset.d.ts +54 -0
  76. package/lib/fields/semantic/text/index.d.ts +13 -0
  77. package/lib/index.d.ts +30 -0
  78. package/lib/utils/batch-dep-update.d.ts +13 -0
  79. package/lib/utils/form-binding.d.ts +11 -0
  80. package/lib/utils/label.d.ts +11 -0
  81. package/lib/utils.d.ts +15 -0
  82. package/package.json +17 -17
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @hi-ui/schema-fields
2
2
 
3
+ ## 4.0.0-experimental.9
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [8dc3817cf]
8
+ - Updated dependencies [8f23e9322]
9
+ - Updated dependencies [b27483796]
10
+ - Updated dependencies [900c6c2f0]
11
+ - Updated dependencies
12
+ - Updated dependencies [f8321b72f]
13
+ - Updated dependencies [fe579e212]
14
+ - Updated dependencies [8561492d5]
15
+ - @hi-ui/date-picker@5.0.0-experimental.1
16
+ - @hi-ui/cascader@5.0.0-experimental.1
17
+ - @hi-ui/check-cascader@5.0.0-experimental.1
18
+ - @hi-ui/check-select@5.0.0-experimental.1
19
+ - @hi-ui/check-tree-select@5.0.0-experimental.1
20
+ - @hi-ui/input@5.0.0-experimental.1
21
+ - @hi-ui/number-input@5.0.0-experimental.1
22
+ - @hi-ui/select@5.0.0-experimental.1
23
+ - @hi-ui/textarea@5.0.0-experimental.1
24
+ - @hi-ui/time-picker@5.0.0-experimental.1
25
+ - @hi-ui/tree-select@5.0.0-experimental.1
26
+ - @hi-ui/counter@5.0.0-experimental.1
27
+ - @hi-ui/schema-option-injector@4.0.0-experimental.5
28
+ - @hi-ui/schema-types@4.0.0-experimental.2
29
+ - @hi-ui/schema-core@4.0.0-experimental.7
30
+
3
31
  ## 4.0.0-experimental.7
4
32
 
5
33
  ### Patch Changes
package/lib/base.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import { InputProps } from '@hi-ui/input';
3
+ import { AbstractProField } from '@hi-ui/schema-core';
4
+ import type { FormItemProps, ProFieldProps, ProFieldRenderCtx, ProFieldRenderCellCtx, ProFieldRenderFooterCellCtx, ProFieldRenderFormItemCtx, ProFieldRenderEditableCtx, ProFieldRenderEditCellCtx, FieldRendererType } from '@hi-ui/schema-core';
5
+ import type { NormalFieldCtxType } from './utils';
6
+ export { ProFieldProps, ProFieldRenderCtx, ProFieldRenderCellCtx, ProFieldRenderFooterCellCtx, ProFieldRenderFormItemCtx, ProFieldRenderEditableCtx, ProFieldRenderEditCellCtx, FieldRendererType, };
7
+ /**
8
+ * 增强型的自定义渲染函数
9
+ * - 用于在字段内部渲染逻辑的基础之上进行额外增强
10
+ */
11
+ export type EnhancedRenderersType = Partial<{
12
+ [K in keyof AbstractProField as K extends 'constructor' ? never : K]: AbstractProField[K] extends AnyFn ? (dom: React.ReactNode, innerCtx: {
13
+ render: ProField;
14
+ data: Parameters<AbstractProField[K]>[0];
15
+ renderCtx: Parameters<AbstractProField[K]>[1];
16
+ }) => React.ReactNode : never;
17
+ }>;
18
+ export declare class ProField extends AbstractProField {
19
+ dftDom: JSX.Element;
20
+ protected getFieldProps<FieldProps extends AnyObject>(dftProps: FieldProps, ctx: NormalFieldCtxType<FieldProps>): FieldProps;
21
+ protected getWrapperProps<WrapperProps extends AnyObject>(dftProps: WrapperProps, ctx: Pick<ProFieldRenderCtx<AnyObject, WrapperProps>, 'field'>): WrapperProps;
22
+ protected getFormItemProps(dftProps: FormItemProps, ctx: Pick<ProFieldRenderFormItemCtx, 'field'>): FormItemProps;
23
+ /**
24
+ * 渲染字符串的内部方法
25
+ * @desc 很多类型的字段最终渲染时都是文本,因此提取一个公共方法到此处
26
+ * @desc 封装了 EllipsisTooltip 的逻辑 */
27
+ protected renderString(text: string, ctx: ProFieldRenderCtx<ProFieldProps>): JSX.Element;
28
+ /** 只读模式的渲染逻辑 */
29
+ render(data: unknown, ctx: ProFieldRenderCtx<AnyType>): JSX.Element;
30
+ /**
31
+ * 表格单元格渲染逻辑
32
+ * @desc 默认直接使用 render 的逻辑 */
33
+ renderCell(data: unknown, ctx: ProFieldRenderCellCtx<AnyType>): JSX.Element;
34
+ /**
35
+ * 表格 Footer 单元格渲染逻辑
36
+ * @desc 没有默认逻辑,需由字段自行实现 */
37
+ renderFooterCell(ctx: ProFieldRenderFooterCellCtx<AnyType>): React.ReactNode;
38
+ renderFormItem(data: null, ctx: ProFieldRenderFormItemCtx<AnyType>): void;
39
+ protected getEditablePlaceholder(data: unknown, ctx: ProFieldRenderEditableCtx<AnyType>): unknown;
40
+ /** 编辑模式的渲染逻辑,在只读与可编辑之间切换 */
41
+ renderEditable(data: unknown, ctx: ProFieldRenderEditableCtx<AnyType>, extraProps?: InputProps): JSX.Element;
42
+ getDftPlaceholder(ctx: NormalFieldCtxType<AnyType>): string | undefined;
43
+ }
44
+ export type FieldMapType = Record<string, typeof ProField>;
@@ -0,0 +1,76 @@
1
+ import React from 'react';
2
+ import type { FieldMapType } from './base';
3
+ import { ProCascader, type ProCascaderProps } from './fields/basic/cascader';
4
+ import { ProCheckCascader, type ProCheckCascaderProps } from './fields/basic/check-cascader';
5
+ import { ProCheckSelect, type ProCheckSelectProps } from './fields/basic/check-select';
6
+ import { ProCheckTreeSelect, type ProCheckTreeSelectProps } from './fields/basic/check-tree-select';
7
+ import { ProCheckbox, type ProCheckboxProps } from './fields/basic/checkbox';
8
+ import { ProCounter, type ProCounterProps } from './fields/basic/counter';
9
+ import { ProDate, type ProDateProps } from './fields/semantic/date';
10
+ import { ProImage, type ProImageProps } from './fields/semantic/image';
11
+ import { ProLink, type ProLinkProps } from './fields/semantic/link';
12
+ import { ProNumber, type ProNumberProps } from './fields/semantic/number';
13
+ import { ProRadio, type ProRadioProps } from './fields/basic/radio';
14
+ import { ProRating, type ProRatingProps } from './fields/basic/rating';
15
+ import { ProSelect, type ProSelectProps } from './fields/basic/select';
16
+ import { ProSlider, type ProSliderProps } from './fields/basic/slider';
17
+ import { ProSwitch, type ProSwitchProps } from './fields/basic/switch';
18
+ import { ProTag, type ProTagProps } from './fields/semantic/tag';
19
+ import { ProText, type ProTextProps } from './fields/semantic/text';
20
+ import { ProTextArea, type ProTextAreaProps } from './fields/basic/textarea';
21
+ import { ProTimePicker, type ProTimePickerProps } from './fields/basic/time-picker';
22
+ import { ProTreeSelect, type ProTreeSelectProps } from './fields/basic/tree-select';
23
+ import { ProUpload, type ProUploadProps } from './fields/basic/upload';
24
+ import { ProNumberRange, type ProNumberRangeProps } from './fields/enhance/number-range';
25
+ export { ProCascader, ProCheckCascader, ProCheckSelect, ProCheckTreeSelect, ProCheckbox, ProCounter, ProDate, ProImage, ProLink, ProNumber, ProRadio, ProRating, ProSelect, ProSlider, ProSwitch, ProTag, ProText, ProTextArea, ProTimePicker, ProTreeSelect, ProUpload, ProNumberRange, };
26
+ export declare const ProFieldMap: {
27
+ cascader: typeof ProCascader;
28
+ 'check-cascader': typeof ProCheckCascader;
29
+ 'check-select': typeof ProCheckSelect;
30
+ 'check-tree-select': typeof ProCheckTreeSelect;
31
+ checkbox: typeof ProCheckbox;
32
+ counter: typeof ProCounter;
33
+ date: typeof ProDate;
34
+ image: typeof ProImage;
35
+ link: typeof ProLink;
36
+ number: typeof ProNumber;
37
+ radio: typeof ProRadio;
38
+ rating: typeof ProRating;
39
+ select: typeof ProSelect;
40
+ slider: typeof ProSlider;
41
+ switch: typeof ProSwitch;
42
+ tag: typeof ProTag;
43
+ text: typeof ProText;
44
+ textarea: typeof ProTextArea;
45
+ 'time-picker': typeof ProTimePicker;
46
+ 'tree-select': typeof ProTreeSelect;
47
+ upload: typeof ProUpload;
48
+ 'number-range': typeof ProNumberRange;
49
+ };
50
+ export type BuiltinFieldMapType = typeof ProFieldMap;
51
+ export type ProFieldMapType = FieldMapType & BuiltinFieldMapType;
52
+ export type ProFieldsProps = {
53
+ cascader: ProCascaderProps;
54
+ 'check-cascader': ProCheckCascaderProps;
55
+ 'check-select': ProCheckSelectProps;
56
+ 'check-tree-select': ProCheckTreeSelectProps;
57
+ checkbox: ProCheckboxProps;
58
+ counter: ProCounterProps;
59
+ date: ProDateProps;
60
+ image: ProImageProps;
61
+ link: ProLinkProps;
62
+ number: ProNumberProps;
63
+ radio: ProRadioProps;
64
+ rating: ProRatingProps;
65
+ select: ProSelectProps;
66
+ slider: ProSliderProps;
67
+ switch: ProSwitchProps;
68
+ tag: ProTagProps;
69
+ text: ProTextProps;
70
+ textarea: ProTextAreaProps;
71
+ 'time-picker': ProTimePickerProps;
72
+ 'tree-select': ProTreeSelectProps;
73
+ upload: ProUploadProps;
74
+ 'number-range': ProNumberRangeProps;
75
+ };
76
+ export declare function BuiltinFieldMapProvider(props: React.PropsWithChildren<unknown>): JSX.Element;
package/lib/bundle.js ADDED
@@ -0,0 +1,66 @@
1
+ /** @LICENSE
2
+ * @hi-ui/schema-fields
3
+ * https://github.com/XiaoMi/hiui/tree/master/packages/schema/schema-fields#readme
4
+ *
5
+ * Copyright (c) HiUI <mi-hiui@xiaomi.com>.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
10
+ import React from 'react';
11
+ import { FieldMapProvider } from './ctx.js';
12
+ import { ProCascader } from './fields/basic/cascader/index.js';
13
+ import { ProCheckCascader } from './fields/basic/check-cascader/index.js';
14
+ import { ProCheckSelect } from './fields/basic/check-select/index.js';
15
+ import { ProCheckTreeSelect } from './fields/basic/check-tree-select/index.js';
16
+ import { ProCheckbox } from './fields/basic/checkbox/index.js';
17
+ import { ProCounter } from './fields/basic/counter/index.js';
18
+ import { ProDate } from './fields/semantic/date/index.js';
19
+ import { ProImage } from './fields/semantic/image/index.js';
20
+ import { ProLink } from './fields/semantic/link/index.js';
21
+ import { ProNumber } from './fields/semantic/number/index.js';
22
+ import { ProRadio } from './fields/basic/radio/index.js';
23
+ import { ProRating } from './fields/basic/rating/index.js';
24
+ import { ProSelect } from './fields/basic/select/index.js';
25
+ import { ProSlider } from './fields/basic/slider/index.js';
26
+ import { ProSwitch } from './fields/basic/switch/index.js';
27
+ import { ProTag } from './fields/semantic/tag/index.js';
28
+ import { ProText } from './fields/semantic/text/index.js';
29
+ import { ProTextArea } from './fields/basic/textarea/index.js';
30
+ import { ProTimePicker } from './fields/basic/time-picker/index.js';
31
+ import { ProTreeSelect } from './fields/basic/tree-select/index.js';
32
+ import { ProUpload } from './fields/basic/upload/index.js';
33
+ import { ProNumberRange } from './fields/enhance/number-range/index.js';
34
+ var ProFieldMap = {
35
+ cascader: ProCascader,
36
+ 'check-cascader': ProCheckCascader,
37
+ 'check-select': ProCheckSelect,
38
+ 'check-tree-select': ProCheckTreeSelect,
39
+ checkbox: ProCheckbox,
40
+ counter: ProCounter,
41
+ date: ProDate,
42
+ image: ProImage,
43
+ link: ProLink,
44
+ number: ProNumber,
45
+ radio: ProRadio,
46
+ rating: ProRating,
47
+ select: ProSelect,
48
+ slider: ProSlider,
49
+ "switch": ProSwitch,
50
+ tag: ProTag,
51
+ text: ProText,
52
+ textarea: ProTextArea,
53
+ 'time-picker': ProTimePicker,
54
+ 'tree-select': ProTreeSelect,
55
+ upload: ProUpload,
56
+ // 'edit-table': ProEditTable,
57
+ 'number-range': ProNumberRange
58
+ // user: ProUser,
59
+ };
60
+
61
+ function BuiltinFieldMapProvider(props) {
62
+ return /*#__PURE__*/React.createElement(FieldMapProvider, {
63
+ fields: ProFieldMap
64
+ }, props.children);
65
+ }
66
+ export { BuiltinFieldMapProvider, ProCascader, ProCheckCascader, ProCheckSelect, ProCheckTreeSelect, ProCheckbox, ProCounter, ProDate, ProFieldMap, ProImage, ProLink, ProNumber, ProNumberRange, ProRadio, ProRating, ProSelect, ProSlider, ProSwitch, ProTag, ProText, ProTextArea, ProTimePicker, ProTreeSelect, ProUpload };
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { ProFieldRenderEditableCtx } from '../../base';
3
+ export declare const AsyncRefillPlaceholder: React.FC<{
4
+ data: string;
5
+ ctx: ProFieldRenderEditableCtx<AnyObject>;
6
+ genInitialOptsData: () => Promise<AnyObject[]>;
7
+ }>;
@@ -0,0 +1,5 @@
1
+ type ImagePreviewProps = {
2
+ images: string[];
3
+ };
4
+ export declare function ImagePreview(props: ImagePreviewProps): JSX.Element;
5
+ export {};
@@ -0,0 +1,49 @@
1
+ /** @LICENSE
2
+ * @hi-ui/schema-fields
3
+ * https://github.com/XiaoMi/hiui/tree/master/packages/schema/schema-fields#readme
4
+ *
5
+ * Copyright (c) HiUI <mi-hiui@xiaomi.com>.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
10
+ import React from 'react';
11
+ import Preview from '@hi-ui/preview';
12
+ import Space from '@hi-ui/space';
13
+ function ImagePreview(props) {
14
+ var images = props.images;
15
+ var _React$useState = React.useState(false),
16
+ visible = _React$useState[0],
17
+ setVisible = _React$useState[1];
18
+ var _React$useState2 = React.useState(0),
19
+ current = _React$useState2[0],
20
+ setCurrent = _React$useState2[1];
21
+ return /*#__PURE__*/React.createElement("div", {
22
+ className: "image-preview"
23
+ }, /*#__PURE__*/React.createElement(Preview, {
24
+ title: current + 1 + "/" + images.length,
25
+ src: images,
26
+ current: current,
27
+ onPreviewChange: setCurrent,
28
+ visible: visible,
29
+ onClose: function onClose() {
30
+ setVisible(false);
31
+ }
32
+ }), /*#__PURE__*/React.createElement(Space, null, images.map(function (url, index) {
33
+ return /*#__PURE__*/React.createElement("div", {
34
+ key: index,
35
+ className: "image-preview__item-wrapper"
36
+ }, /*#__PURE__*/React.createElement("img", {
37
+ src: url,
38
+ style: {
39
+ width: '100%',
40
+ cursor: 'pointer'
41
+ },
42
+ onClick: function onClick() {
43
+ setCurrent(index);
44
+ setVisible(true);
45
+ }
46
+ }));
47
+ })));
48
+ }
49
+ export { ImagePreview };
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export type ReadonlyWrapperProps = {
3
+ children: React.ReactNode;
4
+ dataSet?: Record<string, Primitive | undefined>;
5
+ style?: React.CSSProperties;
6
+ };
7
+ export declare function ReadonlyWrapper(props: ReadonlyWrapperProps): JSX.Element;
8
+ export { ReadonlyWrapper as Span };
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { UploadProps } from '@hi-ui/upload';
3
+ import type { UploadBridgeProps } from './type';
4
+ export { UploadBridgeProps };
5
+ export declare function UploadBridge(props: React.PropsWithChildren<UploadBridgeProps>): React.ReactElement<UploadProps, string | React.JSXElementConstructor<any>>;
@@ -0,0 +1,214 @@
1
+ /** @LICENSE
2
+ * @hi-ui/schema-fields
3
+ * https://github.com/XiaoMi/hiui/tree/master/packages/schema/schema-fields#readme
4
+ *
5
+ * Copyright (c) HiUI <mi-hiui@xiaomi.com>.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
10
+ import _regeneratorRuntime from '@babel/runtime/regenerator';
11
+ import { __rest, __awaiter } from 'tslib';
12
+ import React, { useMemo, useEffect } from 'react';
13
+ import { omit } from 'lodash-es';
14
+ import { useControllableValue } from 'ahooks';
15
+ import { message } from '@hi-ui/message';
16
+ import { useReadonlyRef } from '@hi-ui/schema-hooks';
17
+ import { mergeProps } from '@hi-ui/schema-utils';
18
+ import { toFileList, sliceToMaxCount, genFileIdentifier } from './utils.js';
19
+ var noopOnChange = function noopOnChange() {
20
+ // noopOnChange
21
+ };
22
+ function normalizeProps(props) {
23
+ var value = props.value;
24
+ // value 为字符传时转换为数组;undefined 保持 undefined
25
+ var nextValue = Array.isArray(value) ? value : typeof value === 'string' ? [value] : undefined;
26
+ // 存在 request 方法时,默认使用 json 模式
27
+ var nextMode = props.mode || (props.request ? 'json' : 'formData');
28
+ // maxCount 大于 1 时,默认使用 multiple 模式
29
+ var nextMultiple = props.multiple || (props.maxCount || 0) > 1;
30
+ // 没开启 multiple,也没传 maxCount,则默认限制为 1
31
+ var nextMaxCount = props.maxCount || (!props.multiple ? 1 : undefined);
32
+ return Object.assign(Object.assign({}, props), {
33
+ value: nextValue,
34
+ mode: nextMode,
35
+ multiple: nextMultiple,
36
+ maxCount: nextMaxCount
37
+ });
38
+ }
39
+ function UploadBridge(props) {
40
+ var _this = this;
41
+ var children = props.children,
42
+ restProps = __rest(props, ["children"]);
43
+ var normalizedProps = normalizeProps(restProps);
44
+ var _useControllableValue = useControllableValue(normalizedProps),
45
+ _useControllableValue2 = _useControllableValue[0],
46
+ value = _useControllableValue2 === void 0 ? [] : _useControllableValue2,
47
+ _setValue = _useControllableValue[1];
48
+ var _useMemo = useMemo(function () {
49
+ return toFileList(value);
50
+ }, [value]),
51
+ fileList = _useMemo.fileList,
52
+ fileIdSet = _useMemo.fileIdSet;
53
+ var setValue = function setValue(value) {
54
+ // 只保留<maxCount>个文件
55
+ var sliced = sliceToMaxCount(value, normalizedProps.maxCount, 0);
56
+ var transformed = sliced.map(function (file) {
57
+ if (typeof file === 'string') return {
58
+ url: file,
59
+ fileId: file,
60
+ name: ''
61
+ };else return file;
62
+ });
63
+ _setValue(transformed);
64
+ };
65
+ // 此处的 Set 是给组件卸载的清理阶段有的
66
+ var fileUrlSetRef = useReadonlyRef(function () {
67
+ return new Set();
68
+ });
69
+ if (normalizedProps.mode === 'formData') {
70
+ fileList === null || fileList === void 0 ? void 0 : fileList.forEach(function (_ref) {
71
+ var url = _ref.url;
72
+ return fileUrlSetRef.current.add(url);
73
+ });
74
+ }
75
+ useEffect(function () {
76
+ return function () {
77
+ // 组件卸载时清理所有创建的URL
78
+ // 此处忽略掉这条规则,因为就是需要最新的 fileUrlSetRef
79
+ // eslint-disable-next-line react-hooks/exhaustive-deps
80
+ fileUrlSetRef.current.forEach(function (url) {
81
+ if (url) {
82
+ // url 预期是 blob 协议的本地文件地址
83
+ // 若是外部传入的 http 协议的文件也没事
84
+ // revokeObjectURL 会直接忽略
85
+ URL.revokeObjectURL(url);
86
+ }
87
+ });
88
+ };
89
+ }, [fileUrlSetRef]);
90
+ var customUpload = function customUpload(fileList) {
91
+ return __awaiter(_this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
92
+ var files, uniqueFiles, maxSize, maxSizeInBytes, oversizedFiles, sliced, urls, nextFiles, msg;
93
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
94
+ while (1) {
95
+ switch (_context.prev = _context.next) {
96
+ case 0:
97
+ if (fileList) {
98
+ _context.next = 2;
99
+ break;
100
+ }
101
+ return _context.abrupt("return");
102
+ case 2:
103
+ files = Array.from(fileList); // 1. 文件去重
104
+ // 直接使用已计算的fileList中的fileId
105
+ uniqueFiles = files.filter(function (file) {
106
+ return !(fileIdSet === null || fileIdSet === void 0 ? void 0 : fileIdSet.has(genFileIdentifier(file)));
107
+ });
108
+ if (!(uniqueFiles.length === 0)) {
109
+ _context.next = 7;
110
+ break;
111
+ }
112
+ message.open({
113
+ type: 'warning',
114
+ title: '所选文件已存在'
115
+ });
116
+ return _context.abrupt("return");
117
+ case 7:
118
+ // 2. 检查文件大小 (maxSize单位为KB,需要转换为bytes进行比较)
119
+ maxSize = normalizedProps.maxSize || Infinity;
120
+ maxSizeInBytes = maxSize * 1024;
121
+ oversizedFiles = uniqueFiles.filter(function (file) {
122
+ return file.size > maxSizeInBytes;
123
+ });
124
+ if (!(oversizedFiles.length > 0)) {
125
+ _context.next = 13;
126
+ break;
127
+ }
128
+ message.open({
129
+ type: 'warning',
130
+ title: "\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA" + maxSize + "KB\u9650\u5236"
131
+ });
132
+ return _context.abrupt("return");
133
+ case 13:
134
+ _context.prev = 13;
135
+ if (!(normalizedProps.mode === 'json')) {
136
+ _context.next = 27;
137
+ break;
138
+ }
139
+ if (normalizedProps.request) {
140
+ _context.next = 17;
141
+ break;
142
+ }
143
+ throw new Error('JSON 模式下必须提供 request 方法');
144
+ case 17:
145
+ // 只保留<maxCount - curLength>个文件
146
+ sliced = sliceToMaxCount(uniqueFiles, normalizedProps.maxCount, value.length); // 上传文件并获取URL
147
+ _context.next = 20;
148
+ return normalizedProps.request(sliced);
149
+ case 20:
150
+ urls = _context.sent;
151
+ if (!(!urls || urls.length === 0)) {
152
+ _context.next = 23;
153
+ break;
154
+ }
155
+ return _context.abrupt("return");
156
+ case 23:
157
+ nextFiles = urls.map(function (url, index) {
158
+ var fileId = genFileIdentifier(uniqueFiles[index]);
159
+ if (typeof url === 'string') return {
160
+ url: url,
161
+ fileId: fileId,
162
+ name: ''
163
+ };else return Object.assign(Object.assign({}, url), {
164
+ fileId: fileId
165
+ });
166
+ }); // 更新value
167
+ setValue([].concat(value || [], nextFiles));
168
+ _context.next = 28;
169
+ break;
170
+ case 27:
171
+ // formData模式直接返回File数组
172
+ setValue([].concat(value || [], uniqueFiles));
173
+ case 28:
174
+ _context.next = 35;
175
+ break;
176
+ case 30:
177
+ _context.prev = 30;
178
+ _context.t0 = _context["catch"](13);
179
+ console.log('UploadBridge customUpload request', _context.t0);
180
+ msg = '文件上传失败: ' + (_context.t0 instanceof Error ? _context.t0.message : '未知错误');
181
+ message.open({
182
+ type: 'error',
183
+ title: msg
184
+ });
185
+ case 35:
186
+ case "end":
187
+ return _context.stop();
188
+ }
189
+ }
190
+ }, _callee, null, [[13, 30]]);
191
+ }));
192
+ };
193
+ var handleRemove = function handleRemove(_1, _2, index) {
194
+ // 获取要删除的文件的URL
195
+ var fileToRemove = fileList === null || fileList === void 0 ? void 0 : fileList[index];
196
+ if (fileToRemove === null || fileToRemove === void 0 ? void 0 : fileToRemove.url) URL.revokeObjectURL(fileToRemove.url);
197
+ setValue(value.filter(function (_, idx) {
198
+ return idx !== index;
199
+ }));
200
+ return true;
201
+ };
202
+ var finalProps = mergeProps({
203
+ type: 'default'
204
+ }, omit(normalizedProps, [
205
+ // 移除无关的属性
206
+ 'value', 'defaultValue', 'onChange', 'mode', 'request']));
207
+ return /*#__PURE__*/React.cloneElement(children, Object.assign(Object.assign({}, finalProps), {
208
+ customUpload: customUpload,
209
+ fileList: fileList,
210
+ onChange: noopOnChange,
211
+ onRemove: handleRemove
212
+ }));
213
+ }
214
+ export { UploadBridge };
@@ -0,0 +1,26 @@
1
+ import type { StandardProps } from 'ahooks/es/useControllableValue';
2
+ import type { UploadProps } from '@hi-ui/upload';
3
+ export type BaseFileInfoType = {
4
+ /** 文件名称 */
5
+ name: string;
6
+ /** 包含协议、域名、路径等的完整文件地址 */
7
+ url: string;
8
+ };
9
+ export type UploadFileType = string | File | (BaseFileInfoType & {
10
+ /** 文件唯一标识 */
11
+ fileId?: string;
12
+ });
13
+ export type UploadBridgeProps = Partial<StandardProps<UploadFileType[]>> & Omit<UploadProps, 'customUpload' | 'onChange' | 'fileList' | 'onRemove' | 'maxSize' | 'uploadAction' | 'data' | 'name' | 'method' | 'headers' | 'withCredentials' | 'beforeUpload'> & {
14
+ /**
15
+ * 上传模式
16
+ * @default 'formData'
17
+ * @desc formData 模式时,响应给外部的是【文件】的列表
18
+ * @desc json 模式时,响应给外部的是【文件基本信息对象】的列表
19
+ * @desc json 模式时需传入 request 方法,用来上传文件
20
+ * @desc json 模式下,返回的信息顺序需与上传的顺序一致,否则可能导致自动去重逻辑失效
21
+ */
22
+ mode?: 'formData' | 'json';
23
+ request?: (files: File[]) => Promise<(string | BaseFileInfoType)[]>;
24
+ /** 接收上传的文件体积上限(单位:KB) */
25
+ maxSize?: number;
26
+ };
@@ -0,0 +1,11 @@
1
+ import type { UploadFileItem } from '@hi-ui/upload';
2
+ import type { UploadFileType } from './type';
3
+ export declare function toFileList(file?: UploadFileType | UploadFileType[]): {
4
+ fileIdSet?: undefined;
5
+ fileList?: undefined;
6
+ } | {
7
+ fileIdSet: Set<string>;
8
+ fileList: UploadFileItem[];
9
+ };
10
+ export declare function genFileIdentifier(file: UploadFileType): string;
11
+ export declare function sliceToMaxCount<T>(value: T[], maxCount: number | undefined, curCount?: number): T[];
@@ -0,0 +1,66 @@
1
+ /** @LICENSE
2
+ * @hi-ui/schema-fields
3
+ * https://github.com/XiaoMi/hiui/tree/master/packages/schema/schema-fields#readme
4
+ *
5
+ * Copyright (c) HiUI <mi-hiui@xiaomi.com>.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
10
+ import { extractFileInfo } from '@hi-ui/schema-utils';
11
+ function toFileList(file) {
12
+ if (!file) return {};
13
+ var fileIdSet = new Set();
14
+ var files = Array.isArray(file) ? file : [file];
15
+ var fileList = files.map(function (file) {
16
+ var normalizedFile = typeof file === 'string' ? {
17
+ symbol: file,
18
+ fileId: file,
19
+ url: file
20
+ } : file instanceof File ? {
21
+ symbol: file.name,
22
+ name: file.name,
23
+ fileId: file.name + "-" + file.size + "-" + file.lastModified,
24
+ url: URL.createObjectURL(file)
25
+ } : {
26
+ symbol: file.url,
27
+ name: file.name,
28
+ fileId: file.name + "-" + file.url,
29
+ url: file.url
30
+ };
31
+ var info = extractFileInfo(normalizedFile.symbol);
32
+ // 添加到 fileIdSet
33
+ fileIdSet.add(normalizedFile.fileId);
34
+ return {
35
+ name: normalizedFile.name || info.fullName,
36
+ fileId: normalizedFile.fileId,
37
+ fileType: info.ext,
38
+ uploadState: 'success',
39
+ url: normalizedFile.url
40
+ };
41
+ });
42
+ return {
43
+ fileIdSet: fileIdSet,
44
+ fileList: fileList
45
+ };
46
+ }
47
+ // 文件唯一标识生成函数
48
+ function genFileIdentifier(file) {
49
+ if (file instanceof File) {
50
+ return file.name + "-" + file.size + "-" + file.lastModified;
51
+ } else if (typeof file === 'string') {
52
+ return file;
53
+ } else {
54
+ return file.name + "-" + file.url;
55
+ }
56
+ }
57
+ function sliceToMaxCount(value, maxCount, curCount) {
58
+ if (curCount === void 0) {
59
+ curCount = 0;
60
+ }
61
+ // maxCount 存在时,计算需要保留的文件数量
62
+ var _maxCount = typeof maxCount === 'number' ? maxCount - curCount : undefined;
63
+ var sliceStart = Math.max(value.length - (_maxCount || 0), 0);
64
+ return value.slice(sliceStart);
65
+ }
66
+ export { genFileIdentifier, sliceToMaxCount, toFileList };
package/lib/ctx.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import type { FieldConfigType } from '@hi-ui/schema-core';
3
+ import type { ProField, EnhancedRenderersType } from './base';
4
+ import type { ProFieldMapType } from '.';
5
+ export declare function FieldMapProvider(props: React.PropsWithChildren<{
6
+ fields: Partial<ProFieldMapType>;
7
+ }>): JSX.Element;
8
+ export type UseFieldMapOpts = {
9
+ /** 自定义字段渲染器映射配置 */
10
+ fieldMap?: Partial<ProFieldMapType>;
11
+ };
12
+ export declare function useFieldMap(opts?: UseFieldMapOpts): ProFieldMapType;
13
+ export type MatchFieldClassOpts = UseFieldMapOpts & {
14
+ name?: string;
15
+ field: FieldConfigType;
16
+ fieldMap: ProFieldMapType;
17
+ };
18
+ export declare function matchFieldClass(opts: MatchFieldClassOpts): typeof ProField;
19
+ export declare function getFieldRenderFn<TKey extends keyof EnhancedRenderersType>(Class: typeof ProField, renderKey: TKey): ProField[TKey];
20
+ export declare function matchFieldRenderFn<TKey extends keyof EnhancedRenderersType>(opts: MatchFieldClassOpts & {
21
+ renderKey: TKey;
22
+ }): ProField[TKey];
23
+ export type UseMatchFieldClassOpts = Omit<MatchFieldClassOpts, 'fieldMap'> & {
24
+ fieldMap?: ProFieldMapType;
25
+ };
26
+ export declare function useMatchFieldClass(opts: UseMatchFieldClassOpts): typeof ProField;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { FieldControlType } from '@hi-ui/schema-core';
3
+ export type EditableControlCtxType = Partial<Pick<FieldControlType, 'editable' | 'readonly'>>;
4
+ export declare function EditableControlProvider(props: React.PropsWithChildren<EditableControlCtxType>): JSX.Element;
5
+ export declare function useEditableControlCtx(): Partial<Pick<FieldControlType, "readonly" | "editable">>;