one-design-next 0.0.63 → 0.0.64

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.
package/dist/index.d.ts CHANGED
@@ -43,7 +43,7 @@ export { RuyiLayout, type RuyiLayoutProps, type RuyiMenuItem } from './layout';
43
43
  export { MpLayout, type MpLayoutProps, type MpMenuItem, type MpTabItem, type MpSubTab } from './layout';
44
44
  export { HuxuanLayout, type HuxuanLayoutProps, type HuxuanNavItem, type HuxuanNavChild, type HuxuanActionItem } from './layout';
45
45
  export { default as ScrollArea, type ScrollAreaProps, type ScrollAreaRef } from './scroll-area';
46
- export { default as Select, type SelectProps } from './select';
46
+ export { default as Select, type SelectProps, type TokenPasteResult, type TokenValidationItem, } from './select';
47
47
  export { default as Slider, type SliderProps } from './slider';
48
48
  export { default as Switch, type SwitchProps } from './switch';
49
49
  export { default as Tabs } from './tabs';
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ export type SelectFeedbackState = {
3
+ message: string;
4
+ undoable?: boolean;
5
+ };
6
+ export interface SelectFeedbackProps {
7
+ feedback: SelectFeedbackState | null;
8
+ onUndo?: () => void;
9
+ }
10
+ declare const SelectFeedback: React.FC<SelectFeedbackProps>;
11
+ export default SelectFeedback;
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ var SelectFeedback = function SelectFeedback(_ref) {
3
+ var feedback = _ref.feedback,
4
+ onUndo = _ref.onUndo;
5
+ if (!feedback) {
6
+ return null;
7
+ }
8
+ return /*#__PURE__*/React.createElement("div", {
9
+ className: "odn-select-feedback",
10
+ role: "status",
11
+ "data-odn-select-feedback": true
12
+ }, /*#__PURE__*/React.createElement("span", {
13
+ className: "odn-select-feedback-message"
14
+ }, feedback.message), feedback.undoable ? /*#__PURE__*/React.createElement("button", {
15
+ type: "button",
16
+ className: "odn-select-feedback-undo",
17
+ onClick: onUndo
18
+ }, "\u64A4\u9500") : null);
19
+ };
20
+ export default SelectFeedback;
@@ -3,7 +3,8 @@ import { OptGroup, Option } from 'rc-select';
3
3
  import type { BaseOptionType, DefaultOptionType } from 'rc-select/lib/Select';
4
4
  import React from 'react';
5
5
  import './style';
6
- type RawValue = string | number;
6
+ import { type RawValue, type TokenPasteResult, type TokenValidationItem } from './tokenUtils';
7
+ export type { TokenPasteResult, TokenValidationItem };
7
8
  type SemanticName = 'root';
8
9
  type PopupSemantic = 'root';
9
10
  export interface LabeledValue {
@@ -47,6 +48,32 @@ export interface SelectProps<ValueType = any, OptionType extends BaseOptionType
47
48
  optionCheckPosition?: 'left' | 'right';
48
49
  showInnerSearch?: boolean;
49
50
  optionRender?: RcSelectProps['optionRender'];
51
+ /**
52
+ * 批量粘贴 / 输入分词分隔符。传入后启用增强粘贴:
53
+ * 拆分、去重、未匹配标红保留(可由 tokenMismatch 关闭)、反馈条。
54
+ */
55
+ tokenSeparators?: string[];
56
+ /**
57
+ * 未匹配 token 的处理。
58
+ * - `keep`:标红保留为 invalid chip(默认)
59
+ * - `drop`:丢弃未匹配项(对齐 rc-select multiple 默认行为)
60
+ */
61
+ tokenMismatch?: 'drop' | 'keep';
62
+ /** 是否展示批量粘贴 / 清空反馈条。传入 tokenSeparators 时默认 true */
63
+ tokenFeedback?: boolean;
64
+ /**
65
+ * 自定义批量校验(可异步)。不传则按当前 options 的 label/value 本地匹配。
66
+ */
67
+ validateTokens?: (tokens: string[]) => TokenValidationItem[] | Promise<TokenValidationItem[]>;
68
+ /** 批量粘贴处理完成回调 */
69
+ onTokenPaste?: (result: TokenPasteResult) => void;
70
+ /**
71
+ * 清空全部后是否展示「撤销」。
72
+ * 传入 tokenSeparators 时默认 true;也可单独开启(需 allowClear)。
73
+ */
74
+ clearUndo?: boolean;
75
+ /** 反馈条自动消失时长(ms) */
76
+ feedbackDuration?: number;
50
77
  }
51
78
  export interface SelectButtonProps {
52
79
  /** 是否显示箭头 */
@@ -1,18 +1,25 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
3
+ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
4
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
2
5
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
3
6
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
4
7
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
5
- var _excluded = ["className", "light", "mode", "suffixIcon", "popupClassName", "popupMatchSelectWidth", "visible", "onVisibleChange", "showInnerSearch", "popupRender", "searchValue", "onSearch", "maxCount", "defaultValue", "value", "onChange", "placeholder", "showSearch", "size", "autoClearSearchValue", "optionRender"];
8
+ var _excluded = ["className", "rootClassName", "style", "light", "mode", "suffixIcon", "popupClassName", "popupMatchSelectWidth", "visible", "onVisibleChange", "showInnerSearch", "popupRender", "searchValue", "onSearch", "maxCount", "defaultValue", "value", "onChange", "placeholder", "showSearch", "size", "autoClearSearchValue", "optionRender", "tagRender", "options", "allowClear", "onClear", "tokenSeparators", "tokenMismatch", "tokenFeedback", "validateTokens", "onTokenPaste", "clearUndo", "feedbackDuration", "disabled"];
6
9
  import clsx from 'clsx';
7
10
  import RcSelect, { OptGroup, Option } from 'rc-select';
8
11
  import React, { useEffect, useRef, useState } from 'react';
9
12
  import Checkbox from "../checkbox";
10
13
  import Icon from "../icon";
11
14
  import Popover from "../popover";
15
+ import SelectFeedback from "./SelectFeedback";
12
16
  import "./style";
17
+ import { formatTokenPasteFeedback, readClipboardText, resolveTokenPaste, splitByTokenSeparators, toRawValueList } from "./tokenUtils";
13
18
  import useIcons from "./useIcons";
14
19
  var InternalSelect = function InternalSelect(props, ref) {
15
20
  var className = props.className,
21
+ rootClassName = props.rootClassName,
22
+ style = props.style,
16
23
  light = props.light,
17
24
  mode = props.mode,
18
25
  _props$suffixIcon = props.suffixIcon,
@@ -43,8 +50,26 @@ var InternalSelect = function InternalSelect(props, ref) {
43
50
  _props$autoClearSearc = props.autoClearSearchValue,
44
51
  autoClearSearchValue = _props$autoClearSearc === void 0 ? true : _props$autoClearSearc,
45
52
  _optionRender = props.optionRender,
53
+ tagRender = props.tagRender,
54
+ options = props.options,
55
+ allowClear = props.allowClear,
56
+ onClear = props.onClear,
57
+ tokenSeparators = props.tokenSeparators,
58
+ _props$tokenMismatch = props.tokenMismatch,
59
+ tokenMismatch = _props$tokenMismatch === void 0 ? 'keep' : _props$tokenMismatch,
60
+ tokenFeedback = props.tokenFeedback,
61
+ validateTokens = props.validateTokens,
62
+ onTokenPaste = props.onTokenPaste,
63
+ clearUndo = props.clearUndo,
64
+ _props$feedbackDurati = props.feedbackDuration,
65
+ feedbackDuration = _props$feedbackDurati === void 0 ? 4000 : _props$feedbackDurati,
66
+ disabled = props.disabled,
46
67
  rest = _objectWithoutProperties(props, _excluded);
47
68
  var isMultiple = mode === 'multiple' || mode === 'tags';
69
+ var enableTokenPaste = Boolean(tokenSeparators === null || tokenSeparators === void 0 ? void 0 : tokenSeparators.length) && isMultiple;
70
+ var enableTokenFeedback = tokenFeedback !== null && tokenFeedback !== void 0 ? tokenFeedback : enableTokenPaste;
71
+ var enableClearUndo = clearUndo !== null && clearUndo !== void 0 ? clearUndo : enableTokenPaste;
72
+ var useShell = enableTokenPaste || enableClearUndo || enableTokenFeedback;
48
73
  var _useIcons = useIcons(_objectSpread(_objectSpread({}, rest), {}, {
49
74
  multiple: isMultiple,
50
75
  hasFeedback: false,
@@ -69,13 +94,32 @@ var InternalSelect = function InternalSelect(props, ref) {
69
94
  _useState6 = _slicedToArray(_useState5, 2),
70
95
  searchValue = _useState6[0],
71
96
  setSearchValue = _useState6[1];
97
+ var _useState7 = useState([]),
98
+ _useState8 = _slicedToArray(_useState7, 2),
99
+ invalidValues = _useState8[0],
100
+ setInvalidValues = _useState8[1];
101
+ var _useState9 = useState(null),
102
+ _useState10 = _slicedToArray(_useState9, 2),
103
+ feedback = _useState10[0],
104
+ setFeedback = _useState10[1];
105
+ var undoSnapshotRef = useRef(null);
106
+ var feedbackTimerRef = useRef();
72
107
  var dropdownSearchInputRef = useRef(null);
108
+ var pastingRef = useRef(false);
73
109
  var handleVisibleChange = function handleVisibleChange(bool) {
74
110
  if (visibleProp === undefined) {
75
111
  setVisible(bool);
76
112
  }
77
113
  onVisibleChange === null || onVisibleChange === void 0 || onVisibleChange(bool);
78
114
  };
115
+
116
+ /** 外层 showSearch / 内层 showInnerSearch 共用:受控 searchValue 必须在此回写,否则输入框打不出字 */
117
+ var handleSearch = function handleSearch(text) {
118
+ if (searchValueProp === undefined) {
119
+ setSearchValue(text);
120
+ }
121
+ onSearch === null || onSearch === void 0 || onSearch(text);
122
+ };
79
123
  useEffect(function () {
80
124
  if (valueProp !== undefined) {
81
125
  setValue(valueProp);
@@ -99,25 +143,203 @@ var InternalSelect = function InternalSelect(props, ref) {
99
143
  }, 150);
100
144
  }
101
145
  }, [visible]);
102
- return /*#__PURE__*/React.createElement(RcSelect, _extends({
146
+ useEffect(function () {
147
+ return function () {
148
+ if (feedbackTimerRef.current) {
149
+ clearTimeout(feedbackTimerRef.current);
150
+ }
151
+ };
152
+ }, []);
153
+ var showFeedback = function showFeedback(next) {
154
+ if (!enableTokenFeedback && !(next !== null && next !== void 0 && next.undoable)) {
155
+ setFeedback(null);
156
+ return;
157
+ }
158
+ if (!enableTokenFeedback && !enableClearUndo) {
159
+ setFeedback(null);
160
+ return;
161
+ }
162
+ setFeedback(next);
163
+ if (feedbackTimerRef.current) {
164
+ clearTimeout(feedbackTimerRef.current);
165
+ }
166
+ if (next) {
167
+ feedbackTimerRef.current = setTimeout(function () {
168
+ setFeedback(null);
169
+ undoSnapshotRef.current = null;
170
+ }, feedbackDuration);
171
+ }
172
+ };
173
+ var commitValue = function commitValue(next, option) {
174
+ if (valueProp === undefined) {
175
+ setValue(next);
176
+ }
177
+ _onChange === null || _onChange === void 0 || _onChange(next, option);
178
+ };
179
+ var pruneInvalid = function pruneInvalid(nextValue) {
180
+ var rawList = toRawValueList(nextValue);
181
+ setInvalidValues(function (prev) {
182
+ return prev.filter(function (item) {
183
+ return rawList.some(function (raw) {
184
+ return String(raw) === String(item);
185
+ });
186
+ });
187
+ });
188
+ };
189
+ var handlePasteCapture = /*#__PURE__*/function () {
190
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(event) {
191
+ var text, tokens, currentRaw, result;
192
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
193
+ while (1) switch (_context.prev = _context.next) {
194
+ case 0:
195
+ if (!(!enableTokenPaste || disabled || !(tokenSeparators !== null && tokenSeparators !== void 0 && tokenSeparators.length))) {
196
+ _context.next = 2;
197
+ break;
198
+ }
199
+ return _context.abrupt("return");
200
+ case 2:
201
+ text = readClipboardText(event.clipboardData);
202
+ if (text) {
203
+ _context.next = 5;
204
+ break;
205
+ }
206
+ return _context.abrupt("return");
207
+ case 5:
208
+ tokens = splitByTokenSeparators(text, tokenSeparators);
209
+ if (tokens !== null && tokens !== void 0 && tokens.length) {
210
+ _context.next = 8;
211
+ break;
212
+ }
213
+ return _context.abrupt("return");
214
+ case 8:
215
+ event.preventDefault();
216
+ event.stopPropagation();
217
+ pastingRef.current = true;
218
+ currentRaw = toRawValueList(value);
219
+ _context.next = 14;
220
+ return resolveTokenPaste({
221
+ tokens: tokens,
222
+ currentValue: currentRaw,
223
+ currentInvalid: invalidValues,
224
+ options: options || [],
225
+ tokenMismatch: tokenMismatch,
226
+ maxCount: maxCount,
227
+ validateTokens: validateTokens
228
+ });
229
+ case 14:
230
+ result = _context.sent;
231
+ setInvalidValues(result.nextInvalid);
232
+ commitValue(result.nextValue);
233
+ onTokenPaste === null || onTokenPaste === void 0 || onTokenPaste(result);
234
+ if (enableTokenFeedback) {
235
+ showFeedback({
236
+ message: formatTokenPasteFeedback(result)
237
+ });
238
+ }
239
+ if (autoClearSearchValue) {
240
+ if (searchValueProp === undefined) {
241
+ setSearchValue('');
242
+ }
243
+ onSearch === null || onSearch === void 0 || onSearch('');
244
+ }
245
+
246
+ // 让受控/非受控 onChange 完成后再放开,避免同一次粘贴被 rc-select 再处理
247
+ window.setTimeout(function () {
248
+ pastingRef.current = false;
249
+ }, 0);
250
+ case 21:
251
+ case "end":
252
+ return _context.stop();
253
+ }
254
+ }, _callee);
255
+ }));
256
+ return function handlePasteCapture(_x) {
257
+ return _ref.apply(this, arguments);
258
+ };
259
+ }();
260
+ var handleClear = function handleClear() {
261
+ var current = valueProp === undefined ? value : valueProp;
262
+ var rawList = toRawValueList(current);
263
+ if (enableClearUndo && rawList.length) {
264
+ undoSnapshotRef.current = {
265
+ value: current,
266
+ invalid: _toConsumableArray(invalidValues)
267
+ };
268
+ showFeedback({
269
+ message: "\u5DF2\u6E05\u9664 ".concat(rawList.length, " \u9879"),
270
+ undoable: true
271
+ });
272
+ }
273
+ setInvalidValues([]);
274
+ onClear === null || onClear === void 0 || onClear();
275
+ };
276
+ var handleUndo = function handleUndo() {
277
+ var snapshot = undoSnapshotRef.current;
278
+ if (!snapshot) {
279
+ return;
280
+ }
281
+ undoSnapshotRef.current = null;
282
+ setInvalidValues(snapshot.invalid);
283
+ commitValue(snapshot.value);
284
+ showFeedback(null);
285
+ };
286
+ var mergedTagRender = tagRender || invalidValues.length > 0 ? function (tagProps) {
287
+ var isInvalid = invalidValues.some(function (item) {
288
+ return String(item) === String(tagProps.value);
289
+ });
290
+ if (tagRender) {
291
+ var node = tagRender(tagProps);
292
+ if (!isInvalid || ! /*#__PURE__*/React.isValidElement(node)) {
293
+ return node;
294
+ }
295
+ var element = node;
296
+ return /*#__PURE__*/React.cloneElement(element, {
297
+ className: clsx(element.props.className, 'odn-select-selection-item-invalid'),
298
+ // @ts-expect-error data attr for styling hooks
299
+ 'data-odn-select-tag-invalid': ''
300
+ });
301
+ }
302
+ return /*#__PURE__*/React.createElement("span", {
303
+ className: clsx('odn-select-selection-item', isInvalid && 'odn-select-selection-item-invalid'),
304
+ "data-odn-select-tag-invalid": isInvalid ? '' : undefined
305
+ }, /*#__PURE__*/React.createElement("span", {
306
+ className: "odn-select-selection-item-content"
307
+ }, tagProps.label), tagProps.closable ? /*#__PURE__*/React.createElement("span", {
308
+ className: "odn-select-selection-item-remove",
309
+ onMouseDown: function onMouseDown(e) {
310
+ e.preventDefault();
311
+ e.stopPropagation();
312
+ },
313
+ onClick: tagProps.onClose
314
+ }, typeof removeIcon === 'function' ? removeIcon(tagProps) : removeIcon) : null);
315
+ } : undefined;
316
+ var selectNode = /*#__PURE__*/React.createElement(RcSelect, _extends({
103
317
  ref: ref,
104
318
  prefixCls: "odn-select",
105
319
  className: clsx(className, "odn-select-".concat(size), showInnerSearch && 'odn-select-show-inner-search', light && 'odn-select-light', !light && 'odn-select-outlined'),
320
+ style: useShell ? {
321
+ width: '100%'
322
+ } : style,
106
323
  transitionName: "odn-slide-up",
107
324
  mode: mode,
325
+ options: options,
326
+ allowClear: allowClear,
327
+ onClear: handleClear,
328
+ tokenSeparators: tokenSeparators,
329
+ tagRender: mergedTagRender,
330
+ disabled: disabled,
108
331
  suffixIcon: function suffixIcon(suffixIconProps) {
109
332
  var suffixIconFinal = typeof _suffixIcon === 'function' ? _suffixIcon(suffixIconProps) : _suffixIcon;
110
333
  return /*#__PURE__*/React.createElement(React.Fragment, null, !!maxCount && mode === 'multiple' && Array.isArray(value) && /*#__PURE__*/React.createElement("span", {
111
334
  className: "odn-select-max-count"
112
335
  }, value.length, " / ", maxCount), suffixIconFinal);
113
336
  },
114
- menuItemSelectedIcon: mode === 'multiple' ? function (props) {
115
- var value = props.value,
116
- disabled = props.disabled,
117
- isSelected = props.isSelected;
337
+ menuItemSelectedIcon: mode === 'multiple' ? function (iconProps) {
338
+ var optionDisabled = iconProps.disabled,
339
+ isSelected = iconProps.isSelected;
118
340
  return /*#__PURE__*/React.createElement(Checkbox, {
119
341
  checked: isSelected,
120
- disabled: disabled
342
+ disabled: optionDisabled
121
343
  });
122
344
  } : itemIcon,
123
345
  dropdownClassName: clsx(mode && "odn-select-dropdown-".concat(mode), popupClassName),
@@ -127,18 +349,22 @@ var InternalSelect = function InternalSelect(props, ref) {
127
349
  open: visible,
128
350
  onDropdownVisibleChange: handleVisibleChange,
129
351
  searchValue: searchValue,
352
+ onSearch: handleSearch,
130
353
  value: value,
131
354
  onChange: function onChange(param, option) {
355
+ if (pastingRef.current) {
356
+ // 粘贴路径已在 capture 阶段 commit,忽略 rc-select 二次 onChange
357
+ return;
358
+ }
132
359
  if (valueProp === undefined) {
133
360
  setValue(param);
134
361
  }
362
+ pruneInvalid(param);
135
363
  if (autoClearSearchValue) {
136
364
  if (searchValueProp === undefined) {
137
365
  setSearchValue('');
138
366
  }
139
- if (onSearch) {
140
- onSearch('');
141
- }
367
+ handleSearch('');
142
368
  }
143
369
  _onChange === null || _onChange === void 0 || _onChange(param !== null && param !== void 0 ? param : null, option);
144
370
  },
@@ -156,13 +382,7 @@ var InternalSelect = function InternalSelect(props, ref) {
156
382
  placeholder: "\u8BF7\u8F93\u5165",
157
383
  value: searchValue,
158
384
  onChange: function onChange(e) {
159
- var value = e.target.value;
160
- if (searchValueProp === undefined) {
161
- setSearchValue(value);
162
- }
163
- if (onSearch) {
164
- onSearch(value);
165
- }
385
+ handleSearch(e.target.value);
166
386
  },
167
387
  onKeyDown: function onKeyDown(e) {
168
388
  e.stopPropagation();
@@ -190,30 +410,42 @@ var InternalSelect = function InternalSelect(props, ref) {
190
410
  return finalLabel;
191
411
  }
192
412
  }, rest));
413
+ if (!useShell) {
414
+ return selectNode;
415
+ }
416
+ return /*#__PURE__*/React.createElement("div", {
417
+ className: clsx('odn-select-shell', rootClassName),
418
+ style: style,
419
+ onPasteCapture: enableTokenPaste ? handlePasteCapture : undefined,
420
+ "data-odn-select-shell": true
421
+ }, selectNode, /*#__PURE__*/React.createElement(SelectFeedback, {
422
+ feedback: enableTokenFeedback || feedback !== null && feedback !== void 0 && feedback.undoable && enableClearUndo ? feedback : null,
423
+ onUndo: handleUndo
424
+ }));
193
425
  };
194
426
 
195
427
  // Select.Button 组件接口
196
428
 
197
429
  // Select.Button 组件
198
- var SelectButton = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
199
- var _ref$showArrow = _ref.showArrow,
200
- showArrow = _ref$showArrow === void 0 ? true : _ref$showArrow,
201
- _ref$size = _ref.size,
202
- size = _ref$size === void 0 ? 'middle' : _ref$size,
203
- _ref$disabled = _ref.disabled,
204
- disabled = _ref$disabled === void 0 ? false : _ref$disabled,
205
- prefix = _ref.prefix,
206
- _ref$placeholder = _ref.placeholder,
207
- placeholder = _ref$placeholder === void 0 ? '请选择' : _ref$placeholder,
208
- value = _ref.value,
209
- _ref$active = _ref.active,
210
- active = _ref$active === void 0 ? false : _ref$active,
211
- _ref$allowClear = _ref.allowClear,
212
- allowClear = _ref$allowClear === void 0 ? false : _ref$allowClear,
213
- onClick = _ref.onClick,
214
- onClear = _ref.onClear,
215
- className = _ref.className,
216
- style = _ref.style;
430
+ var SelectButton = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
431
+ var _ref2$showArrow = _ref2.showArrow,
432
+ showArrow = _ref2$showArrow === void 0 ? true : _ref2$showArrow,
433
+ _ref2$size = _ref2.size,
434
+ size = _ref2$size === void 0 ? 'middle' : _ref2$size,
435
+ _ref2$disabled = _ref2.disabled,
436
+ disabled = _ref2$disabled === void 0 ? false : _ref2$disabled,
437
+ prefix = _ref2.prefix,
438
+ _ref2$placeholder = _ref2.placeholder,
439
+ placeholder = _ref2$placeholder === void 0 ? '请选择' : _ref2$placeholder,
440
+ value = _ref2.value,
441
+ _ref2$active = _ref2.active,
442
+ active = _ref2$active === void 0 ? false : _ref2$active,
443
+ _ref2$allowClear = _ref2.allowClear,
444
+ allowClear = _ref2$allowClear === void 0 ? false : _ref2$allowClear,
445
+ onClick = _ref2.onClick,
446
+ onClear = _ref2.onClear,
447
+ className = _ref2.className,
448
+ style = _ref2.style;
217
449
  var buttonClasses = clsx('odn-select-button odn-select odn-select-outlined odn-select-single odn-select-allow-clear odn-select-show-arrow', "odn-select-button-".concat(size), {
218
450
  'odn-select-button-disabled': disabled,
219
451
  'odn-select-open': active
@@ -28,6 +28,15 @@ html {
28
28
  --odn-select-option-selected-color: var(--odn-color-black-12);
29
29
  --odn-select-option-selected-bg: var(--odn-color-blue-1);
30
30
  --odn-selection-item-font-weight: 400;
31
+ --odn-select-multiple-item-invalid-bg: var(--odn-color-red-1);
32
+ --odn-select-multiple-item-invalid-border-color: color-mix(
33
+ in srgb,
34
+ var(--odn-color-error) 40%,
35
+ transparent
36
+ );
37
+ --odn-select-multiple-item-invalid-color: var(--odn-color-error);
38
+ --odn-select-feedback-bg: var(--odn-color-brand-1);
39
+ --odn-select-feedback-color: var(--odn-color-primary);
31
40
  }
32
41
 
33
42
  .odn-select.odn-select-in-form-item {
@@ -663,11 +672,20 @@ html {
663
672
  }
664
673
 
665
674
  .odn-select-multiple .odn-select-selection-overflow-item-suffix {
675
+ /* 默认隐藏:多选主推 showInnerSearch;外层 showSearch 时后缀才是输入框载体 */
666
676
  display: none;
667
677
  min-height: var(--odn-select-multiple-item-height);
668
678
  margin-block: var(--odn-select-internal_fixed_item_margin);
669
679
  }
670
680
 
681
+ .odn-select-multiple.odn-select-show-search .odn-select-selection-overflow-item-suffix {
682
+ display: inline-flex;
683
+ align-items: center;
684
+ max-width: 100%;
685
+ flex: 1 1 auto;
686
+ min-width: 60px;
687
+ }
688
+
671
689
  .odn-select-multiple .odn-select-selection-search {
672
690
  display: inline-flex;
673
691
  position: relative;
@@ -1778,4 +1796,59 @@ html {
1778
1796
 
1779
1797
  .odn-select-selection-overflow-item-rest > span {
1780
1798
  min-width: 0;
1799
+ }
1800
+
1801
+ /* ===== 批量粘贴 / 反馈壳 ===== */
1802
+ .odn-select-shell {
1803
+ display: inline-flex;
1804
+ flex-direction: column;
1805
+ align-items: stretch;
1806
+ max-width: 100%;
1807
+ vertical-align: top;
1808
+ }
1809
+
1810
+ .odn-select-shell .odn-select {
1811
+ width: 100%;
1812
+ }
1813
+
1814
+ .odn-select-multiple .odn-select-selection-overflow .odn-select-selection-item.odn-select-selection-item-invalid,
1815
+ .odn-select-selection-item.odn-select-selection-item-invalid {
1816
+ color: var(--odn-select-multiple-item-invalid-color);
1817
+ background: var(--odn-select-multiple-item-invalid-bg);
1818
+ border: 1px solid var(--odn-select-multiple-item-invalid-border-color);
1819
+ }
1820
+
1821
+ .odn-select-feedback {
1822
+ display: flex;
1823
+ align-items: center;
1824
+ gap: 8px;
1825
+ margin-top: 8px;
1826
+ padding: 8px 12px;
1827
+ border-radius: var(--odn-select-border-radius-sm);
1828
+ background: var(--odn-select-feedback-bg);
1829
+ color: var(--odn-select-feedback-color);
1830
+ font-size: 13px;
1831
+ line-height: 20px;
1832
+ }
1833
+
1834
+ .odn-select-feedback-message {
1835
+ flex: 1;
1836
+ min-width: 0;
1837
+ }
1838
+
1839
+ .odn-select-feedback-undo {
1840
+ flex: none;
1841
+ margin: 0;
1842
+ padding: 0;
1843
+ border: none;
1844
+ background: transparent;
1845
+ color: var(--odn-select-feedback-color);
1846
+ font-size: 13px;
1847
+ line-height: 20px;
1848
+ text-decoration: underline;
1849
+ cursor: pointer;
1850
+ }
1851
+
1852
+ .odn-select-feedback-undo:hover {
1853
+ opacity: 0.85;
1781
1854
  }
@@ -0,0 +1,36 @@
1
+ import type { DefaultOptionType } from 'rc-select/lib/Select';
2
+ import type { ReactNode } from 'react';
3
+ export type RawValue = string | number;
4
+ export type TokenValidationItem = {
5
+ /** 原始粘贴片段 */
6
+ token: string;
7
+ /** 匹配到的 value;未匹配时可省略 */
8
+ value?: RawValue;
9
+ /** 展示文案 */
10
+ label?: ReactNode;
11
+ /** 是否有效(在候选内或业务认可) */
12
+ valid: boolean;
13
+ };
14
+ export type TokenPasteResult = {
15
+ added: RawValue[];
16
+ duplicated: string[];
17
+ invalid: string[];
18
+ nextValue: RawValue[];
19
+ nextInvalid: RawValue[];
20
+ };
21
+ /** 与 rc-select getSeparatedContent 对齐:任一分隔符命中才拆分 */
22
+ export declare function readClipboardText(clipboardData: DataTransfer | null): string;
23
+ export declare function splitByTokenSeparators(text: string, separators: string[]): string[] | null;
24
+ export declare function flattenSelectOptions(options?: DefaultOptionType[]): DefaultOptionType[];
25
+ export declare function matchOptionByToken(token: string, options: DefaultOptionType[]): DefaultOptionType | null;
26
+ export declare function toRawValueList(value: unknown): RawValue[];
27
+ export declare function resolveTokenPaste(params: {
28
+ tokens: string[];
29
+ currentValue: RawValue[];
30
+ currentInvalid: RawValue[];
31
+ options: DefaultOptionType[];
32
+ tokenMismatch: 'drop' | 'keep';
33
+ maxCount?: number;
34
+ validateTokens?: (tokens: string[]) => TokenValidationItem[] | Promise<TokenValidationItem[]>;
35
+ }): Promise<TokenPasteResult>;
36
+ export declare function formatTokenPasteFeedback(result: TokenPasteResult): string;
@@ -0,0 +1,256 @@
1
+ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
2
+ import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
3
+ import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
4
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
5
+ import _typeof from "@babel/runtime/helpers/esm/typeof";
6
+ import _toArray from "@babel/runtime/helpers/esm/toArray";
7
+ /** 与 rc-select getSeparatedContent 对齐:任一分隔符命中才拆分 */
8
+ export function readClipboardText(clipboardData) {
9
+ if (!clipboardData) {
10
+ return '';
11
+ }
12
+ return clipboardData.getData('text/plain') || clipboardData.getData('text') || '';
13
+ }
14
+ export function splitByTokenSeparators(text, separators) {
15
+ if (!(separators !== null && separators !== void 0 && separators.length) || !text) {
16
+ return null;
17
+ }
18
+ var matched = false;
19
+ var separate = function separate(str, tokens) {
20
+ if (!tokens.length) {
21
+ return [str];
22
+ }
23
+ var _tokens = _toArray(tokens),
24
+ token = _tokens[0],
25
+ rest = _tokens.slice(1);
26
+ var list = str.split(token);
27
+ matched = matched || list.length > 1;
28
+ return list.reduce(function (prev, unit) {
29
+ return prev.concat(separate(unit, rest));
30
+ }, []).filter(Boolean);
31
+ };
32
+ var list = separate(text, separators);
33
+ return matched ? list.map(function (s) {
34
+ return s.trim();
35
+ }).filter(Boolean) : null;
36
+ }
37
+ export function flattenSelectOptions() {
38
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
39
+ var result = [];
40
+ var walk = function walk(list) {
41
+ list.forEach(function (opt) {
42
+ var _opt$options;
43
+ if ((_opt$options = opt.options) !== null && _opt$options !== void 0 && _opt$options.length) {
44
+ walk(opt.options);
45
+ return;
46
+ }
47
+ result.push(opt);
48
+ });
49
+ };
50
+ walk(options);
51
+ return result;
52
+ }
53
+ export function matchOptionByToken(token, options) {
54
+ var _flat$find;
55
+ var normalized = token.trim().toLowerCase();
56
+ if (!normalized) {
57
+ return null;
58
+ }
59
+ var flat = flattenSelectOptions(options);
60
+ return (_flat$find = flat.find(function (opt) {
61
+ var value = opt.value;
62
+ var label = opt.label;
63
+ return String(value).toLowerCase() === normalized || String(label !== null && label !== void 0 ? label : '').toLowerCase() === normalized;
64
+ })) !== null && _flat$find !== void 0 ? _flat$find : null;
65
+ }
66
+ export function toRawValueList(value) {
67
+ if (value === undefined || value === null || value === '') {
68
+ return [];
69
+ }
70
+ if (Array.isArray(value)) {
71
+ return value.map(function (item) {
72
+ if (item !== null && _typeof(item) === 'object' && 'value' in item) {
73
+ return item.value;
74
+ }
75
+ return item;
76
+ });
77
+ }
78
+ if (_typeof(value) === 'object' && value !== null && 'value' in value) {
79
+ return [value.value];
80
+ }
81
+ return [value];
82
+ }
83
+ export function resolveTokenPaste(_x) {
84
+ return _resolveTokenPaste.apply(this, arguments);
85
+ }
86
+ function _resolveTokenPaste() {
87
+ _resolveTokenPaste = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(params) {
88
+ var tokens, currentValue, currentInvalid, options, tokenMismatch, maxCount, validateTokens, validated, nextValue, nextInvalid, added, duplicated, invalid, hasValue, _iterator, _step, _loop, _ret;
89
+ return _regeneratorRuntime().wrap(function _callee$(_context2) {
90
+ while (1) switch (_context2.prev = _context2.next) {
91
+ case 0:
92
+ tokens = params.tokens, currentValue = params.currentValue, currentInvalid = params.currentInvalid, options = params.options, tokenMismatch = params.tokenMismatch, maxCount = params.maxCount, validateTokens = params.validateTokens;
93
+ if (!validateTokens) {
94
+ _context2.next = 7;
95
+ break;
96
+ }
97
+ _context2.next = 4;
98
+ return validateTokens(tokens);
99
+ case 4:
100
+ _context2.t0 = _context2.sent;
101
+ _context2.next = 8;
102
+ break;
103
+ case 7:
104
+ _context2.t0 = tokens.map(function (token) {
105
+ var hit = matchOptionByToken(token, options);
106
+ return hit ? {
107
+ token: token,
108
+ value: hit.value,
109
+ label: hit.label,
110
+ valid: true
111
+ } : {
112
+ token: token,
113
+ value: token,
114
+ label: token,
115
+ valid: false
116
+ };
117
+ });
118
+ case 8:
119
+ validated = _context2.t0;
120
+ nextValue = _toConsumableArray(currentValue);
121
+ nextInvalid = _toConsumableArray(currentInvalid);
122
+ added = [];
123
+ duplicated = [];
124
+ invalid = [];
125
+ hasValue = function hasValue(v) {
126
+ return nextValue.some(function (item) {
127
+ return String(item) === String(v);
128
+ });
129
+ };
130
+ _iterator = _createForOfIteratorHelper(validated);
131
+ _context2.prev = 16;
132
+ _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
133
+ var _item$value2;
134
+ var item, _item$value, _value, idx, value;
135
+ return _regeneratorRuntime().wrap(function _loop$(_context) {
136
+ while (1) switch (_context.prev = _context.next) {
137
+ case 0:
138
+ item = _step.value;
139
+ if (!(typeof maxCount === 'number' && nextValue.length >= maxCount)) {
140
+ _context.next = 3;
141
+ break;
142
+ }
143
+ return _context.abrupt("return", 0);
144
+ case 3:
145
+ if (!item.valid) {
146
+ _context.next = 13;
147
+ break;
148
+ }
149
+ _value = (_item$value = item.value) !== null && _item$value !== void 0 ? _item$value : item.token;
150
+ if (!hasValue(_value)) {
151
+ _context.next = 8;
152
+ break;
153
+ }
154
+ duplicated.push(item.token);
155
+ return _context.abrupt("return", 1);
156
+ case 8:
157
+ nextValue.push(_value);
158
+ added.push(_value);
159
+ // 若此前是 invalid,转正后移除
160
+ idx = nextInvalid.findIndex(function (v) {
161
+ return String(v) === String(_value);
162
+ });
163
+ if (idx >= 0) {
164
+ nextInvalid.splice(idx, 1);
165
+ }
166
+ return _context.abrupt("return", 1);
167
+ case 13:
168
+ // 未匹配
169
+ invalid.push(item.token);
170
+ if (!(tokenMismatch === 'drop')) {
171
+ _context.next = 16;
172
+ break;
173
+ }
174
+ return _context.abrupt("return", 1);
175
+ case 16:
176
+ value = (_item$value2 = item.value) !== null && _item$value2 !== void 0 ? _item$value2 : item.token;
177
+ if (!hasValue(value)) {
178
+ _context.next = 20;
179
+ break;
180
+ }
181
+ duplicated.push(item.token);
182
+ return _context.abrupt("return", 1);
183
+ case 20:
184
+ nextValue.push(value);
185
+ added.push(value);
186
+ if (!nextInvalid.some(function (v) {
187
+ return String(v) === String(value);
188
+ })) {
189
+ nextInvalid.push(value);
190
+ }
191
+ case 23:
192
+ case "end":
193
+ return _context.stop();
194
+ }
195
+ }, _loop);
196
+ });
197
+ _iterator.s();
198
+ case 19:
199
+ if ((_step = _iterator.n()).done) {
200
+ _context2.next = 28;
201
+ break;
202
+ }
203
+ return _context2.delegateYield(_loop(), "t1", 21);
204
+ case 21:
205
+ _ret = _context2.t1;
206
+ if (!(_ret === 0)) {
207
+ _context2.next = 24;
208
+ break;
209
+ }
210
+ return _context2.abrupt("break", 28);
211
+ case 24:
212
+ if (!(_ret === 1)) {
213
+ _context2.next = 26;
214
+ break;
215
+ }
216
+ return _context2.abrupt("continue", 26);
217
+ case 26:
218
+ _context2.next = 19;
219
+ break;
220
+ case 28:
221
+ _context2.next = 33;
222
+ break;
223
+ case 30:
224
+ _context2.prev = 30;
225
+ _context2.t2 = _context2["catch"](16);
226
+ _iterator.e(_context2.t2);
227
+ case 33:
228
+ _context2.prev = 33;
229
+ _iterator.f();
230
+ return _context2.finish(33);
231
+ case 36:
232
+ return _context2.abrupt("return", {
233
+ added: added,
234
+ duplicated: duplicated,
235
+ invalid: invalid,
236
+ nextValue: nextValue,
237
+ nextInvalid: nextInvalid
238
+ });
239
+ case 37:
240
+ case "end":
241
+ return _context2.stop();
242
+ }
243
+ }, _callee, null, [[16, 30, 33, 36]]);
244
+ }));
245
+ return _resolveTokenPaste.apply(this, arguments);
246
+ }
247
+ export function formatTokenPasteFeedback(result) {
248
+ var parts = ["\u5DF2\u6DFB\u52A0 ".concat(result.added.length, " \u9879")];
249
+ if (result.duplicated.length) {
250
+ parts.push("\u5FFD\u7565\u91CD\u590D ".concat(result.duplicated.length, " \u9879"));
251
+ }
252
+ if (result.invalid.length) {
253
+ parts.push(result.nextInvalid.length ? "\u672A\u5339\u914D ".concat(result.invalid.length, " \u9879\u5DF2\u6807\u7EA2") : "\u672A\u5339\u914D ".concat(result.invalid.length, " \u9879\u5DF2\u5FFD\u7565"));
254
+ }
255
+ return parts.join(' · ');
256
+ }
package/package.json CHANGED
@@ -1,56 +1,52 @@
1
1
  {
2
2
  "name": "one-design-next",
3
- "version": "0.0.63",
3
+ "version": "0.0.64",
4
4
  "description": "One Design Next from TAD@tencent.com",
5
- "packageManager": "pnpm@11.8.0",
5
+ "license": "MIT",
6
+ "type": "module",
6
7
  "module": "dist/index.js",
7
8
  "types": "dist/index.d.ts",
8
- "type": "module",
9
+ "files": [
10
+ "dist"
11
+ ],
9
12
  "scripts": {
10
- "start": "npm run dev",
11
- "dev": "npm run build:variables && npm run build:benchmark && npm run build:feedback && dumi dev",
12
- "dev:recover": "bash scripts/after-git-switch.sh && npm run dev",
13
+ "benchmark": "node scripts/run-benchmark.mjs",
14
+ "benchmark:auto": "node scripts/run-benchmark.mjs --auto-only",
15
+ "benchmark:compare": "node scripts/run-benchmark.mjs --compare",
13
16
  "build": "father build && npm run build:styles",
17
+ "build:benchmark": "node scripts/build-benchmark.mjs",
18
+ "build:feedback": "node scripts/build-feedback.mjs",
14
19
  "build:skills": "bash skills/build.sh",
15
- "build:watch": "father dev",
16
20
  "build:styles": "node scripts/build-styles.js",
17
21
  "build:variables": "node scripts/build-variables.js",
18
- "generate:llms": "node scripts/generate-llms.mjs",
22
+ "build:watch": "father dev",
23
+ "create-component": "node scripts/create-component.js",
24
+ "create-skill": "node scripts/create-skill.mjs",
25
+ "dev": "npm run build:variables && npm run build:benchmark && npm run build:feedback && dumi dev",
26
+ "dev:recover": "bash scripts/after-git-switch.sh && npm run dev",
19
27
  "docs:build": "npm run build:variables && npm run build:benchmark && npm run build:feedback && npm run generate:llms && dumi build",
20
28
  "docs:preview": "dumi preview",
21
- "prepare": "husky install && dumi setup",
22
29
  "doctor": "father doctor",
30
+ "feedback:server": "node scripts/feedback-server.mjs",
31
+ "feedback:submit": "node scripts/feedback-submit.mjs",
32
+ "gen:test": "node scripts/gen-test.mjs",
33
+ "generate:llms": "node scripts/generate-llms.mjs",
23
34
  "lint": "npm run lint:es && npm run lint:css",
24
35
  "lint:css": "stylelint \"{components,test}/**/*.{css,scss}\"",
25
36
  "lint:es": "eslint \"{components,test}/**/*.{js,jsx,ts,tsx}\"",
37
+ "prepare": "husky install && dumi setup",
26
38
  "prepublishOnly": "father doctor && npm run build",
27
- "create-component": "node scripts/create-component.js",
28
- "gen:test": "node scripts/gen-test.mjs",
39
+ "release": "node scripts/release.mjs",
40
+ "start": "npm run dev",
29
41
  "test": "vitest",
42
+ "test:a11y": "echo 'axe-core smoke run(待 P5 接入)'",
43
+ "test:changed": "vitest run --changed",
30
44
  "test:ci": "vitest run",
31
- "test:visual:update": "UPDATE_VISUAL=1 vitest run",
32
45
  "test:visual:docker": "bash scripts/visual-baseline-docker.sh",
46
+ "test:visual:update": "UPDATE_VISUAL=1 vitest run",
33
47
  "test:visual:update:docker": "bash scripts/visual-baseline-docker.sh update",
34
- "test:changed": "vitest run --changed",
35
- "test:a11y": "echo 'axe-core smoke run(待 P5 接入)'",
36
- "typecheck": "tsc -p tsconfig.ci.json",
37
- "build:benchmark": "node scripts/build-benchmark.mjs",
38
- "benchmark": "node scripts/run-benchmark.mjs",
39
- "benchmark:compare": "node scripts/run-benchmark.mjs --compare",
40
- "benchmark:auto": "node scripts/run-benchmark.mjs --auto-only",
41
- "create-skill": "node scripts/create-skill.mjs",
42
- "build:feedback": "node scripts/build-feedback.mjs",
43
- "feedback:server": "node scripts/feedback-server.mjs",
44
- "feedback:submit": "node scripts/feedback-submit.mjs",
45
- "release": "node scripts/release.mjs"
48
+ "typecheck": "tsc -p tsconfig.ci.json"
46
49
  },
47
- "authors": [
48
- "yijiejiang@tencent.com"
49
- ],
50
- "license": "MIT",
51
- "files": [
52
- "dist"
53
- ],
54
50
  "commitlint": {
55
51
  "extends": [
56
52
  "@commitlint/config-conventional"
@@ -64,24 +60,39 @@
64
60
  "stylelint --fix",
65
61
  "prettier --write"
66
62
  ],
67
- "*.{js,jsx}": [
63
+ "{components,test}/**/*.{js,jsx}": [
68
64
  "eslint --fix",
69
65
  "prettier --write"
70
66
  ],
71
- "*.{ts,tsx}": [
67
+ "{components,test}/**/*.{ts,tsx}": [
72
68
  "eslint --fix",
73
69
  "prettier --parser=typescript --write"
74
70
  ]
75
71
  },
76
- "publishConfig": {
77
- "access": "public"
78
- },
79
- "engines": {
80
- "node": ">=16.0.0"
81
- },
82
- "peerDependencies": {
83
- "react": "~16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc",
84
- "react-dom": "~16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
72
+ "dependencies": {
73
+ "@babel/runtime": "^7.29.2",
74
+ "@base-ui/react": "^1.6.0",
75
+ "@daypicker/react": "^10.0.1",
76
+ "@floating-ui/react": "^0.27.19",
77
+ "@number-flow/react": "^0.6.0",
78
+ "@paper-design/shaders-react": "^0.0.76",
79
+ "@radix-ui/react-slot": "^1.3.0",
80
+ "classnames": "^2.5.1",
81
+ "clsx": "^2.1.1",
82
+ "echarts-for-react": "^3.0.6",
83
+ "ldrs": "^1.1.9",
84
+ "motion": "^12.40.0",
85
+ "rc-cascader": "^3.34.0",
86
+ "rc-select": "^14.16.8",
87
+ "rc-slider": "^11.1.9",
88
+ "rc-table": "^7.55.1",
89
+ "rc-tree": "^5.13.1",
90
+ "rc-tree-select": "^5.27.0",
91
+ "rc-util": "^5.44.4",
92
+ "rc-virtual-list": "^3.19.2",
93
+ "react-d3-cloud": "^1.0.6",
94
+ "react-markdown": "^10.1.0",
95
+ "remark-gfm": "^4.0.1"
85
96
  },
86
97
  "devDependencies": {
87
98
  "@commitlint/cli": "^17.1.2",
@@ -146,29 +157,18 @@
146
157
  "vite": "^8.0.16",
147
158
  "vitest": "^4.1.9"
148
159
  },
149
- "dependencies": {
150
- "@babel/runtime": "^7.29.2",
151
- "@base-ui/react": "^1.6.0",
152
- "@daypicker/react": "^10.0.1",
153
- "@floating-ui/react": "^0.27.19",
154
- "@number-flow/react": "^0.6.0",
155
- "@paper-design/shaders-react": "^0.0.76",
156
- "@radix-ui/react-slot": "^1.3.0",
157
- "classnames": "^2.5.1",
158
- "clsx": "^2.1.1",
159
- "echarts-for-react": "^3.0.6",
160
- "ldrs": "^1.1.9",
161
- "motion": "^12.40.0",
162
- "rc-cascader": "^3.34.0",
163
- "rc-select": "^14.16.8",
164
- "rc-slider": "^11.1.9",
165
- "rc-table": "^7.55.1",
166
- "rc-tree": "^5.13.1",
167
- "rc-tree-select": "^5.27.0",
168
- "rc-util": "^5.44.4",
169
- "rc-virtual-list": "^3.19.2",
170
- "react-d3-cloud": "^1.0.6",
171
- "react-markdown": "^10.1.0",
172
- "remark-gfm": "^4.0.1"
173
- }
160
+ "peerDependencies": {
161
+ "react": "~16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc",
162
+ "react-dom": "~16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
163
+ },
164
+ "packageManager": "pnpm@11.8.0",
165
+ "engines": {
166
+ "node": ">=16.0.0"
167
+ },
168
+ "publishConfig": {
169
+ "access": "public"
170
+ },
171
+ "authors": [
172
+ "yijiejiang@tencent.com"
173
+ ]
174
174
  }