assui 3.2.106 → 3.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ export interface ComplexValSelectOptionType extends Omit<DefaultOptionType, 'val
8
8
  children?: ComplexValSelectOptionType[];
9
9
  options?: Omit<ComplexValSelectOptionType, 'children' | 'options'>[];
10
10
  }
11
- /** 判断optionsValue是否是引用类型 */
11
+ /** 判断 options 的 value 中是否包含引用类型(对象或数组) */
12
12
  export declare const isReferenceTypeOption: (options?: ComplexValSelectOptionType[]) => boolean;
13
13
  export interface ComplexValSelectProps<T> extends Omit<SelectProps, 'value' | 'onChange' | 'options'> {
14
14
  value?: T;
@@ -40,27 +40,36 @@ import Select from "antd/es/select";
40
40
  import classNames from 'classnames';
41
41
  import ArrowDownOutlined from "a-icons/es/ArrowDownOutlined";
42
42
  import useControllableValue from "ahooks/es/useControllableValue";
43
+ import stableStringify from "aa-utils/es/stableStringify";
44
+ import { isNil } from 'lodash';
43
45
  var Option = Select.Option;
44
46
  export { Option };
45
- var _formatOptions = function formatOptions(dateSource) {
46
- if (dateSource) {
47
- var options = dateSource.map(function (item) {
48
- var otherProps = item.options ? {
49
- options: _formatOptions(item.options)
50
- } : {};
51
- return __assign(__assign(__assign({}, item), {
52
- label: item.label,
53
- value: isUndefined(item.value) ? undefined : JSON.stringify(item.value)
54
- }), otherProps);
55
- });
56
- return options;
47
+ // 核心防御:防止非标准 JSON 字符串(如 tags 模式下手敲的纯文本或 undefined)导致页面崩溃
48
+ var safeParse = function safeParse(str) {
49
+ if (typeof str !== 'string') return str;
50
+ try {
51
+ return JSON.parse(str);
52
+ } catch (_a) {
53
+ return str; // 解析失败直接返回原字符串
57
54
  }
58
- return dateSource;
59
55
  };
60
- /** 判断optionsValue是否是引用类型 */
56
+ /** 递归格式化 options,将复杂 value 序列化为字符串 */
57
+ var _formatOptions = function formatOptions(dataSource) {
58
+ if (!dataSource) return dataSource;
59
+ return dataSource.map(function (item) {
60
+ var otherProps = item.options ? {
61
+ options: _formatOptions(item.options)
62
+ } : {};
63
+ return __assign(__assign(__assign({}, item), {
64
+ label: item.label,
65
+ value: isUndefined(item.value) ? undefined : stableStringify(item.value)
66
+ }), otherProps);
67
+ });
68
+ };
69
+ /** 判断 options 的 value 中是否包含引用类型(对象或数组) */
61
70
  export var isReferenceTypeOption = function isReferenceTypeOption(options) {
62
- var resultBoolean = some(options, function (item) {
63
- if (item.value) {
71
+ return some(options, function (item) {
72
+ if (!isUndefined(item.value)) {
64
73
  return isArray(item.value) || isObject(item.value);
65
74
  }
66
75
  if (item.options) {
@@ -70,42 +79,48 @@ export var isReferenceTypeOption = function isReferenceTypeOption(options) {
70
79
  }
71
80
  return false;
72
81
  });
73
- return resultBoolean;
74
82
  };
75
83
  var ComplexValSelect = /*#__PURE__*/React.forwardRef(function (props, ref) {
76
84
  var _a = __read(useControllableValue(props), 2),
77
85
  value = _a[0],
78
86
  setValue = _a[1];
79
87
  var options = props.options,
80
- onSelect = props.onSelect;
88
+ onSelect = props.onSelect,
89
+ mode = props.mode;
81
90
  var selectRef = React.useRef(null);
82
91
  React.useImperativeHandle(ref, function () {
83
92
  return selectRef.current;
84
93
  });
85
- // 判断是否需要将optionValue转为JSON字符串
94
+ // 判断是否为多选模式 (multiple 或 tags)
95
+ var isMultiple = mode === 'multiple' || mode === 'tags';
96
+ // 判断是否需要将 option 的 value 转为 JSON 字符串
86
97
  var isReferenceTypeVal = isReferenceTypeOption(options);
87
98
  var finalOptions = isReferenceTypeVal ? _formatOptions(options) : options;
99
+ // 处理选中值改变:将底层传出的字符串安全地 parse 回真实的数据结构
88
100
  var handleChange = function handleChange(val, option) {
89
101
  var nextVal = val;
90
- if (val && isReferenceTypeVal) {
91
- nextVal = isArray(val) ? val.map(function (item) {
92
- return JSON.parse(item);
93
- }) : JSON.parse(val);
102
+ if (!isNil(val) && isReferenceTypeVal) {
103
+ nextVal = isMultiple && isArray(val) ? val.map(function (item) {
104
+ return safeParse(item);
105
+ }) : safeParse(val);
94
106
  }
95
107
  setValue(nextVal, option);
96
108
  };
97
109
  var handleSelect = function handleSelect(val, option) {
98
- var nextVal = val && isReferenceTypeVal ? JSON.parse(val) : val;
110
+ var nextVal = !isNil(val) && isReferenceTypeVal ? safeParse(val) : val;
99
111
  onSelect === null || onSelect === void 0 ? void 0 : onSelect(nextVal, option);
100
112
  };
113
+ // 处理回显展示值:将传入的真实数据结构 stringify 成字符串去匹配底层 Option
101
114
  var displayValue = React.useMemo(function () {
102
- if (value && isReferenceTypeVal) {
103
- return isArray(value) ? value.map(function (v) {
104
- return JSON.stringify(v);
105
- }) : JSON.stringify(value);
115
+ if (!isNil(value) && isReferenceTypeVal) {
116
+ return isMultiple && isArray(value) ? value.map(function (v) {
117
+ // 在 tags 模式下,如果 v 已经是手敲的基础字符串,直接放行,避免产生多余的双引号
118
+ if (mode === 'tags' && typeof v === 'string') return v;
119
+ return stableStringify(v);
120
+ }) : stableStringify(value);
106
121
  }
107
122
  return value;
108
- }, [value, isReferenceTypeVal]);
123
+ }, [value, isReferenceTypeVal, isMultiple, mode]);
109
124
  return /*#__PURE__*/React.createElement(Select, __assign({
110
125
  ref: selectRef,
111
126
  className: classNames('complex-val-select', props === null || props === void 0 ? void 0 : props.className),
@@ -8,7 +8,7 @@ export interface ComplexValSelectOptionType extends Omit<DefaultOptionType, 'val
8
8
  children?: ComplexValSelectOptionType[];
9
9
  options?: Omit<ComplexValSelectOptionType, 'children' | 'options'>[];
10
10
  }
11
- /** 判断optionsValue是否是引用类型 */
11
+ /** 判断 options 的 value 中是否包含引用类型(对象或数组) */
12
12
  export declare const isReferenceTypeOption: (options?: ComplexValSelectOptionType[]) => boolean;
13
13
  export interface ComplexValSelectProps<T> extends Omit<SelectProps, 'value' | 'onChange' | 'options'> {
14
14
  value?: T;
@@ -82,27 +82,36 @@ var select_1 = __importDefault(require("antd/lib/select"));
82
82
  var classnames_1 = __importDefault(require("classnames"));
83
83
  var ArrowDownOutlined_1 = __importDefault(require("a-icons/lib/ArrowDownOutlined"));
84
84
  var useControllableValue_1 = __importDefault(require("ahooks/lib/useControllableValue"));
85
+ var stableStringify_1 = __importDefault(require("aa-utils/lib/stableStringify"));
86
+ var lodash_1 = require("lodash");
85
87
  var Option = select_1["default"].Option;
86
88
  exports.Option = Option;
87
- var _formatOptions = function formatOptions(dateSource) {
88
- if (dateSource) {
89
- var options = dateSource.map(function (item) {
90
- var otherProps = item.options ? {
91
- options: _formatOptions(item.options)
92
- } : {};
93
- return __assign(__assign(__assign({}, item), {
94
- label: item.label,
95
- value: (0, isUndefined_1["default"])(item.value) ? undefined : JSON.stringify(item.value)
96
- }), otherProps);
97
- });
98
- return options;
89
+ // 核心防御:防止非标准 JSON 字符串(如 tags 模式下手敲的纯文本或 undefined)导致页面崩溃
90
+ var safeParse = function safeParse(str) {
91
+ if (typeof str !== 'string') return str;
92
+ try {
93
+ return JSON.parse(str);
94
+ } catch (_a) {
95
+ return str; // 解析失败直接返回原字符串
99
96
  }
100
- return dateSource;
101
97
  };
102
- /** 判断optionsValue是否是引用类型 */
98
+ /** 递归格式化 options,将复杂 value 序列化为字符串 */
99
+ var _formatOptions = function formatOptions(dataSource) {
100
+ if (!dataSource) return dataSource;
101
+ return dataSource.map(function (item) {
102
+ var otherProps = item.options ? {
103
+ options: _formatOptions(item.options)
104
+ } : {};
105
+ return __assign(__assign(__assign({}, item), {
106
+ label: item.label,
107
+ value: (0, isUndefined_1["default"])(item.value) ? undefined : (0, stableStringify_1["default"])(item.value)
108
+ }), otherProps);
109
+ });
110
+ };
111
+ /** 判断 options 的 value 中是否包含引用类型(对象或数组) */
103
112
  var isReferenceTypeOption = function isReferenceTypeOption(options) {
104
- var resultBoolean = (0, some_1["default"])(options, function (item) {
105
- if (item.value) {
113
+ return (0, some_1["default"])(options, function (item) {
114
+ if (!(0, isUndefined_1["default"])(item.value)) {
106
115
  return (0, isArray_1["default"])(item.value) || (0, isObject_1["default"])(item.value);
107
116
  }
108
117
  if (item.options) {
@@ -112,7 +121,6 @@ var isReferenceTypeOption = function isReferenceTypeOption(options) {
112
121
  }
113
122
  return false;
114
123
  });
115
- return resultBoolean;
116
124
  };
117
125
  exports.isReferenceTypeOption = isReferenceTypeOption;
118
126
  var ComplexValSelect = React.forwardRef(function (props, ref) {
@@ -120,35 +128,42 @@ var ComplexValSelect = React.forwardRef(function (props, ref) {
120
128
  value = _a[0],
121
129
  setValue = _a[1];
122
130
  var options = props.options,
123
- onSelect = props.onSelect;
131
+ onSelect = props.onSelect,
132
+ mode = props.mode;
124
133
  var selectRef = React.useRef(null);
125
134
  React.useImperativeHandle(ref, function () {
126
135
  return selectRef.current;
127
136
  });
128
- // 判断是否需要将optionValue转为JSON字符串
137
+ // 判断是否为多选模式 (multiple 或 tags)
138
+ var isMultiple = mode === 'multiple' || mode === 'tags';
139
+ // 判断是否需要将 option 的 value 转为 JSON 字符串
129
140
  var isReferenceTypeVal = (0, exports.isReferenceTypeOption)(options);
130
141
  var finalOptions = isReferenceTypeVal ? _formatOptions(options) : options;
142
+ // 处理选中值改变:将底层传出的字符串安全地 parse 回真实的数据结构
131
143
  var handleChange = function handleChange(val, option) {
132
144
  var nextVal = val;
133
- if (val && isReferenceTypeVal) {
134
- nextVal = (0, isArray_1["default"])(val) ? val.map(function (item) {
135
- return JSON.parse(item);
136
- }) : JSON.parse(val);
145
+ if (!(0, lodash_1.isNil)(val) && isReferenceTypeVal) {
146
+ nextVal = isMultiple && (0, isArray_1["default"])(val) ? val.map(function (item) {
147
+ return safeParse(item);
148
+ }) : safeParse(val);
137
149
  }
138
150
  setValue(nextVal, option);
139
151
  };
140
152
  var handleSelect = function handleSelect(val, option) {
141
- var nextVal = val && isReferenceTypeVal ? JSON.parse(val) : val;
153
+ var nextVal = !(0, lodash_1.isNil)(val) && isReferenceTypeVal ? safeParse(val) : val;
142
154
  onSelect === null || onSelect === void 0 ? void 0 : onSelect(nextVal, option);
143
155
  };
156
+ // 处理回显展示值:将传入的真实数据结构 stringify 成字符串去匹配底层 Option
144
157
  var displayValue = React.useMemo(function () {
145
- if (value && isReferenceTypeVal) {
146
- return (0, isArray_1["default"])(value) ? value.map(function (v) {
147
- return JSON.stringify(v);
148
- }) : JSON.stringify(value);
158
+ if (!(0, lodash_1.isNil)(value) && isReferenceTypeVal) {
159
+ return isMultiple && (0, isArray_1["default"])(value) ? value.map(function (v) {
160
+ // 在 tags 模式下,如果 v 已经是手敲的基础字符串,直接放行,避免产生多余的双引号
161
+ if (mode === 'tags' && typeof v === 'string') return v;
162
+ return (0, stableStringify_1["default"])(v);
163
+ }) : (0, stableStringify_1["default"])(value);
149
164
  }
150
165
  return value;
151
- }, [value, isReferenceTypeVal]);
166
+ }, [value, isReferenceTypeVal, isMultiple, mode]);
152
167
  return React.createElement(select_1["default"], __assign({
153
168
  ref: selectRef,
154
169
  className: (0, classnames_1["default"])('complex-val-select', props === null || props === void 0 ? void 0 : props.className),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assui",
3
- "version": "3.2.106",
3
+ "version": "3.3.2",
4
4
  "description": "react ui library",
5
5
  "author": "jason <usochen@gmail.com>",
6
6
  "main": "./lib/index.js",
@@ -36,7 +36,7 @@
36
36
  "@types/react-color": "^3.0.6",
37
37
  "@types/react-resizable": "^3.0.0",
38
38
  "a-icons": "^1.2.68",
39
- "aa-utils": "^2.1.34",
39
+ "aa-utils": "^2.1.35",
40
40
  "ahooks": "^3.9.5",
41
41
  "bignumber.js": "^9.0.1",
42
42
  "copy-to-clipboard": "^3.3.1",
@@ -87,5 +87,5 @@
87
87
  "node": ">=10.0.0"
88
88
  },
89
89
  "license": "MIT",
90
- "gitHead": "a733655570b6114592c403f0a0e9df03f438e686"
90
+ "gitHead": "6c3acd10c334b5f131583dd1624c3b38fc0fd620"
91
91
  }