@douyinfe/semi-foundation 2.93.0-alpha.0 → 2.94.0

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 (77) hide show
  1. package/aiChatInput/foundation.ts +3 -1
  2. package/autoComplete/foundation.ts +3 -2
  3. package/cascader/foundation.ts +8 -3
  4. package/collapsible/foundation.ts +1 -0
  5. package/datePicker/datePicker.scss +2 -2
  6. package/descriptions/foundation.ts +3 -1
  7. package/form/foundation.ts +61 -29
  8. package/form/interface.ts +9 -2
  9. package/input/textareaFoundation.ts +34 -1
  10. package/lib/cjs/aiChatInput/foundation.js +3 -1
  11. package/lib/cjs/autoComplete/foundation.d.ts +1 -0
  12. package/lib/cjs/autoComplete/foundation.js +1 -1
  13. package/lib/cjs/cascader/foundation.d.ts +1 -0
  14. package/lib/cjs/cascader/foundation.js +8 -3
  15. package/lib/cjs/collapsible/foundation.d.ts +1 -0
  16. package/lib/cjs/datePicker/datePicker.css +2 -2
  17. package/lib/cjs/datePicker/datePicker.scss +2 -2
  18. package/lib/cjs/descriptions/foundation.js +3 -1
  19. package/lib/cjs/form/foundation.d.ts +5 -5
  20. package/lib/cjs/form/foundation.js +58 -21
  21. package/lib/cjs/form/interface.d.ts +8 -2
  22. package/lib/cjs/input/textareaFoundation.d.ts +12 -0
  23. package/lib/cjs/input/textareaFoundation.js +39 -0
  24. package/lib/cjs/modal/modalFoundation.d.ts +6 -0
  25. package/lib/cjs/modal/modalFoundation.js +36 -4
  26. package/lib/cjs/pagination/foundation.js +28 -7
  27. package/lib/cjs/pincode/foundation.d.ts +1 -1
  28. package/lib/cjs/resizable/resizable.css +3 -3
  29. package/lib/cjs/resizable/variables.scss +2 -2
  30. package/lib/cjs/select/foundation.d.ts +1 -1
  31. package/lib/cjs/select/foundation.js +19 -8
  32. package/lib/cjs/steps/bacisSteps.scss +8 -2
  33. package/lib/cjs/steps/steps.css +6 -0
  34. package/lib/cjs/upload/foundation.d.ts +8 -1
  35. package/lib/cjs/upload/foundation.js +70 -22
  36. package/lib/cjs/utils/escapeHtml.d.ts +9 -0
  37. package/lib/cjs/utils/escapeHtml.js +90 -0
  38. package/lib/cjs/utils/object.js +3 -1
  39. package/lib/es/aiChatInput/foundation.js +3 -1
  40. package/lib/es/autoComplete/foundation.d.ts +1 -0
  41. package/lib/es/autoComplete/foundation.js +1 -1
  42. package/lib/es/cascader/foundation.d.ts +1 -0
  43. package/lib/es/cascader/foundation.js +8 -3
  44. package/lib/es/collapsible/foundation.d.ts +1 -0
  45. package/lib/es/datePicker/datePicker.css +2 -2
  46. package/lib/es/datePicker/datePicker.scss +2 -2
  47. package/lib/es/descriptions/foundation.js +3 -1
  48. package/lib/es/form/foundation.d.ts +5 -5
  49. package/lib/es/form/foundation.js +58 -21
  50. package/lib/es/form/interface.d.ts +8 -2
  51. package/lib/es/input/textareaFoundation.d.ts +12 -0
  52. package/lib/es/input/textareaFoundation.js +39 -0
  53. package/lib/es/modal/modalFoundation.d.ts +6 -0
  54. package/lib/es/modal/modalFoundation.js +36 -4
  55. package/lib/es/pagination/foundation.js +28 -7
  56. package/lib/es/pincode/foundation.d.ts +1 -1
  57. package/lib/es/resizable/resizable.css +3 -3
  58. package/lib/es/resizable/variables.scss +2 -2
  59. package/lib/es/select/foundation.d.ts +1 -1
  60. package/lib/es/select/foundation.js +19 -8
  61. package/lib/es/steps/bacisSteps.scss +8 -2
  62. package/lib/es/steps/steps.css +6 -0
  63. package/lib/es/upload/foundation.d.ts +8 -1
  64. package/lib/es/upload/foundation.js +70 -22
  65. package/lib/es/utils/escapeHtml.d.ts +9 -0
  66. package/lib/es/utils/escapeHtml.js +84 -0
  67. package/lib/es/utils/object.js +3 -1
  68. package/modal/modalFoundation.ts +33 -32
  69. package/package.json +35 -5
  70. package/pagination/foundation.ts +25 -7
  71. package/pincode/foundation.ts +1 -1
  72. package/resizable/variables.scss +2 -2
  73. package/select/foundation.ts +19 -8
  74. package/steps/bacisSteps.scss +8 -2
  75. package/upload/foundation.ts +81 -24
  76. package/utils/escapeHtml.ts +94 -0
  77. package/utils/object.ts +3 -1
@@ -110,6 +110,7 @@ export interface BasicCascaderProps {
110
110
  disableStrictly?: boolean;
111
111
  leafOnly?: boolean;
112
112
  enableLeafClick?: boolean;
113
+ clickToSelect?: boolean;
113
114
  preventScroll?: boolean;
114
115
  virtualizeInSearch?: Virtualize;
115
116
  checkRelation?: string;
@@ -548,7 +548,8 @@ export default class CascaderFoundation extends BaseFoundation {
548
548
  changeOnSelect: allowChange,
549
549
  filterLeafOnly,
550
550
  multiple,
551
- enableLeafClick
551
+ enableLeafClick,
552
+ clickToSelect
552
553
  } = this.getProps();
553
554
  const {
554
555
  keyEntities,
@@ -564,7 +565,9 @@ export default class CascaderFoundation extends BaseFoundation {
564
565
  const activeKeys = keyEntities[key].path;
565
566
  const selectedKey = [key];
566
567
  const hasChanged = key !== [...selectedKeys][0];
567
- if (!isLeaf && !allowChange && !isSearching) {
568
+ // When clickToSelect is enabled in multiple mode, allow clicking non-leaf nodes to select
569
+ // In single mode, changeOnSelect (allowChange) controls this behavior
570
+ if (!isLeaf && !allowChange && !isSearching && !(multiple && clickToSelect)) {
568
571
  this._adapter.updateStates({
569
572
  activeKeys: new Set(activeKeys)
570
573
  });
@@ -575,7 +578,9 @@ export default class CascaderFoundation extends BaseFoundation {
575
578
  this._adapter.updateStates({
576
579
  activeKeys: new Set(activeKeys)
577
580
  });
578
- if (isLeaf && enableLeafClick) {
581
+ // clickToSelect: click any node to select (takes precedence over enableLeafClick)
582
+ // enableLeafClick: click leaf node to select
583
+ if (clickToSelect || isLeaf && enableLeafClick) {
579
584
  this.onItemCheckboxClick(item);
580
585
  }
581
586
  } else {
@@ -5,6 +5,7 @@ export interface CollapsibleFoundationProps {
5
5
  keepDOM?: boolean;
6
6
  className?: string;
7
7
  collapseHeight?: number;
8
+ collapseHeightAdaptive?: boolean;
8
9
  reCalcKey?: number | string;
9
10
  id?: string;
10
11
  fade?: boolean;
@@ -624,10 +624,10 @@
624
624
  height: fit-content;
625
625
  border: none;
626
626
  }
627
- .semi-datepicker-range-input-wrapper .semi-input-wrapper:active {
627
+ .semi-datepicker-range-input-wrapper .semi-input-wrapper:active:not(#neverExistElement) {
628
628
  background-color: transparent;
629
629
  }
630
- .semi-datepicker-range-input-wrapper .semi-input-wrapper:hover {
630
+ .semi-datepicker-range-input-wrapper .semi-input-wrapper:hover:not(#neverExistElement) {
631
631
  background-color: transparent;
632
632
  }
633
633
  .semi-datepicker-range-input-wrapper-focus {
@@ -937,11 +937,11 @@ $module-list: #{$prefix}-scrolllist;
937
937
  height: fit-content;
938
938
  border: none;
939
939
 
940
- &:active {
940
+ &:active:not(#neverExistElement) {
941
941
  background-color: transparent;
942
942
  }
943
943
 
944
- &:hover {
944
+ &:hover:not(#neverExistElement) {
945
945
  background-color: transparent;
946
946
  }
947
947
  }
@@ -10,12 +10,14 @@ export default class DescriptionsFoundation extends BaseFoundation {
10
10
  children
11
11
  } = this.getProps();
12
12
  const columns = this._adapter.getColumns();
13
+ // Filter out hidden items before grouping
14
+ const visibleColumns = columns.filter(item => !item.hidden);
13
15
  const horizontalList = [];
14
16
  const curSpan = {
15
17
  totalSpan: 0,
16
18
  itemList: []
17
19
  };
18
- for (const item of columns) {
20
+ for (const item of visibleColumns) {
19
21
  curSpan.totalSpan += item.span || 1;
20
22
  curSpan.itemList.push(item);
21
23
  if (curSpan.totalSpan >= column) {
@@ -1,6 +1,6 @@
1
1
  import BaseFoundation from '../base/foundation';
2
2
  import { Options as ScrollIntoViewOptions } from 'scroll-into-view-if-needed';
3
- import { BaseFormAdapter, FormState, CallOpts, FieldState, FieldStaff, ComponentProps, setValuesConfig, ArrayFieldStaff } from './interface';
3
+ import { BaseFormAdapter, FormState, CallOpts, FieldState, FieldStaff, ComponentProps, setValuesConfig, ArrayFieldStaff, ValidateOptions } from './interface';
4
4
  export type { BaseFormAdapter };
5
5
  type ScrollToErrorOpts = {
6
6
  field?: string;
@@ -21,9 +21,9 @@ export default class FormFoundation extends BaseFoundation<BaseFormAdapter> {
21
21
  unRegisterArrayField(arrayField: string): void;
22
22
  getArrayField(arrayField: string): ArrayFieldStaff;
23
23
  updateArrayField(arrayField: string, updateValue: any): void;
24
- validate(fieldPaths?: Array<string>): Promise<unknown>;
25
- _formValidate(): Promise<unknown>;
26
- _fieldsValidate(fieldPaths: Array<string>): Promise<unknown>;
24
+ validate(fieldPaths?: Array<string> | ValidateOptions): Promise<unknown>;
25
+ _formValidate(silent?: boolean): Promise<unknown>;
26
+ _fieldsValidate(fieldPaths: Array<string>, silent?: boolean): Promise<unknown>;
27
27
  submit(e?: any): void;
28
28
  /**
29
29
  * Case A:
@@ -77,7 +77,7 @@ export default class FormFoundation extends BaseFoundation<BaseFormAdapter> {
77
77
  };
78
78
  getFormApi(): {
79
79
  reset: (fields?: Array<string>) => void;
80
- validate: (fields?: Array<string>) => Promise<unknown>;
80
+ validate: (fields?: Array<string> | ValidateOptions) => Promise<unknown>;
81
81
  getValue: (field?: string) => any;
82
82
  getValues: () => any;
83
83
  getFormState: () => FormState<any>;
@@ -129,14 +129,27 @@ export default class FormFoundation extends BaseFoundation {
129
129
  const {
130
130
  validateFields
131
131
  } = this.getProps();
132
+ // Parse options
133
+ let fields;
134
+ let silent = false;
135
+ if (fieldPaths && !Array.isArray(fieldPaths)) {
136
+ // It's a ValidateOptions object
137
+ const options = fieldPaths;
138
+ fields = options.fields;
139
+ silent = options.silent || false;
140
+ } else {
141
+ // It's an array of fields (or undefined)
142
+ fields = fieldPaths;
143
+ }
132
144
  if (validateFields && _isFunction(validateFields)) {
133
- return this._formValidate();
145
+ return this._formValidate(silent);
134
146
  } else {
135
- return this._fieldsValidate(fieldPaths);
147
+ return this._fieldsValidate(fields, silent);
136
148
  }
137
149
  }
138
150
  // form level validate
139
151
  _formValidate() {
152
+ let silent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
140
153
  const {
141
154
  values
142
155
  } = this.data;
@@ -154,41 +167,52 @@ export default class FormFoundation extends BaseFoundation {
154
167
  if (!maybePromisedErrors) {
155
168
  const _values = this._adapter.cloneDeep(values);
156
169
  resolve(_values);
157
- this.injectErrorToField({});
170
+ if (!silent) {
171
+ this.injectErrorToField({});
172
+ }
158
173
  } else if (isPromise(maybePromisedErrors)) {
159
174
  maybePromisedErrors.then(result => {
160
175
  // validate success,clear error
161
176
  if (!result) {
162
177
  const _values = this._adapter.cloneDeep(values);
163
178
  resolve(_values);
164
- this.injectErrorToField({});
179
+ if (!silent) {
180
+ this.injectErrorToField({});
181
+ }
165
182
  } else {
166
- this.data.errors = result;
167
- this._adapter.notifyChange(this.data);
168
- this.injectErrorToField(result);
169
- this._adapter.forceUpdate();
170
- this._autoScroll(100);
183
+ if (!silent) {
184
+ this.data.errors = result;
185
+ this._adapter.notifyChange(this.data);
186
+ this.injectErrorToField(result);
187
+ this._adapter.forceUpdate();
188
+ this._autoScroll(100);
189
+ }
171
190
  reject(result);
172
191
  }
173
192
  }, errors => {
174
193
  // validate failed
175
- // this._adapter.notifyChange(this.data);
176
- this._autoScroll(100);
194
+ if (!silent) {
195
+ // this._adapter.notifyChange(this.data);
196
+ this._autoScroll(100);
197
+ }
177
198
  reject(errors);
178
199
  });
179
200
  } else {
180
201
  // TODO: current design, returning an empty object will be considered a checksum failure and will be rejected. Only returning an empty string will be considered a success, consider resetting it in 1.0?
181
- this.data.errors = maybePromisedErrors;
182
- this.injectErrorToField(maybePromisedErrors);
183
- this._adapter.notifyChange(this.data);
184
- this._adapter.forceUpdate();
185
- this._autoScroll(100);
202
+ if (!silent) {
203
+ this.data.errors = maybePromisedErrors;
204
+ this.injectErrorToField(maybePromisedErrors);
205
+ this._adapter.notifyChange(this.data);
206
+ this._adapter.forceUpdate();
207
+ this._autoScroll(100);
208
+ }
186
209
  reject(maybePromisedErrors);
187
210
  }
188
211
  });
189
212
  }
190
213
  // field level validate
191
214
  _fieldsValidate(fieldPaths) {
215
+ let silent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
192
216
  const {
193
217
  values
194
218
  } = this.data;
@@ -200,24 +224,37 @@ export default class FormFoundation extends BaseFoundation {
200
224
  // Call each fieldApi for verification
201
225
  const fieldValue = this.getValue(fieldPath);
202
226
  // When centralized verification, no need to trigger forceUpdate and notify
227
+ // Each field skips individual updates; a single forceUpdate fires after all resolve.
203
228
  const opts = {
204
229
  notNotify: true,
205
- notUpdate: true
230
+ notUpdate: true,
231
+ silent
206
232
  };
207
233
  const validateResult = field.fieldApi.validate(fieldValue, opts);
208
234
  promiseSet.push(validateResult);
209
- field.fieldApi.setTouched(true, opts);
235
+ // Only set touched when not in silent mode
236
+ if (!silent) {
237
+ field.fieldApi.setTouched(true, {
238
+ notNotify: true,
239
+ notUpdate: true
240
+ });
241
+ }
210
242
  });
211
243
  Promise.all(promiseSet).then(() => {
212
244
  // After the centralized verification is completed, trigger notify and forceUpdate once.
213
- this._adapter.notifyChange(this.data);
214
- this._adapter.forceUpdate();
245
+ // But skip UI updates in silent mode
246
+ if (!silent) {
247
+ this._adapter.notifyChange(this.data);
248
+ this._adapter.forceUpdate();
249
+ }
215
250
  const errors = this.getError();
216
251
  if (this._isValid(targetFields)) {
217
252
  const _values = this._adapter.cloneDeep(values);
218
253
  resolve(_values);
219
254
  } else {
220
- this._autoScroll();
255
+ if (!silent) {
256
+ this._autoScroll();
257
+ }
221
258
  reject(errors);
222
259
  }
223
260
  });
@@ -42,6 +42,12 @@ export type ScrollToErrorOptions<K> = {
42
42
  index?: number;
43
43
  scrollOpts?: ScrollIntoViewOptions;
44
44
  };
45
+ export interface ValidateOptions<K extends keyof any = keyof any> {
46
+ /** Fields to validate, if not specified, validate all fields */
47
+ fields?: Array<K>;
48
+ /** Whether to validate silently (without updating UI or setting touched state) */
49
+ silent?: boolean;
50
+ }
45
51
  export interface BaseFormApi<T extends object = any> {
46
52
  /** get value of field */
47
53
  getValue: <P extends FieldPath<T>>(field?: P) => FieldPathValue<T, P>;
@@ -65,8 +71,8 @@ export interface BaseFormApi<T extends object = any> {
65
71
  submitForm: () => void;
66
72
  /** reset form manual */
67
73
  reset: (fields?: Array<string>) => void;
68
- /** trigger validate manual */
69
- validate: <K extends keyof T, Params extends Array<K>, V extends Params[number]>(fields?: Params) => Promise<{
74
+ /** trigger validate manual */
75
+ validate: <K extends keyof T, Params extends Array<K>, V extends Params[number]>(fields?: Params | ValidateOptions<K>) => Promise<{
70
76
  [R in V]: T[R];
71
77
  }>;
72
78
  getInitValue: <K extends keyof T>(field: K) => any;
@@ -18,6 +18,8 @@ export interface TextAreaAdapter extends Partial<DefaultAdapter>, Partial<TextAr
18
18
  notifyPressEnter(e: any): void;
19
19
  getRef(): HTMLInputElement;
20
20
  notifyHeightUpdate(e: any): void;
21
+ focusInput(): void;
22
+ isEventTarget(e: any): boolean;
21
23
  }
22
24
  export default class TextAreaFoundation extends BaseFoundation<TextAreaAdapter> {
23
25
  static get textAreaDefaultAdapter(): {
@@ -67,4 +69,14 @@ export default class TextAreaFoundation extends BaseFoundation<TextAreaAdapter>
67
69
  handleMouseLeave(e: any): void;
68
70
  isAllowClear(): boolean;
69
71
  handleClear(e: any): void;
72
+ /**
73
+ * trigger when click textarea wrapper
74
+ * @param {Event} e
75
+ */
76
+ handleClick(e: any): void;
77
+ /**
78
+ * trigger when click textarea counter
79
+ * @param {Event} e
80
+ */
81
+ handleCounterClick(e: any): void;
70
82
  }
@@ -270,4 +270,43 @@ export default class TextAreaFoundation extends BaseFoundation {
270
270
  this._adapter.notifyClear(e);
271
271
  this.stopPropagation(e);
272
272
  }
273
+ /**
274
+ * trigger when click textarea wrapper
275
+ * @param {Event} e
276
+ */
277
+ handleClick(e) {
278
+ const {
279
+ disabled,
280
+ readonly
281
+ } = this._adapter.getProps();
282
+ const {
283
+ isFocus
284
+ } = this._adapter.getStates();
285
+ if (disabled || readonly || isFocus) {
286
+ return;
287
+ }
288
+ // do not handle bubbling up events
289
+ if (this._adapter.isEventTarget(e)) {
290
+ this._adapter.focusInput();
291
+ this._adapter.toggleFocusing(true);
292
+ }
293
+ }
294
+ /**
295
+ * trigger when click textarea counter
296
+ * @param {Event} e
297
+ */
298
+ handleCounterClick(e) {
299
+ const {
300
+ disabled,
301
+ readonly
302
+ } = this._adapter.getProps();
303
+ const {
304
+ isFocus
305
+ } = this._adapter.getStates();
306
+ if (disabled || readonly || isFocus) {
307
+ return;
308
+ }
309
+ this._adapter.focusInput();
310
+ this._adapter.toggleFocusing(true);
311
+ }
273
312
  }
@@ -61,10 +61,16 @@ export interface ModalState {
61
61
  onCancelReturnPromiseStatus?: "pending" | "fulfilled" | "rejected";
62
62
  }
63
63
  export default class ModalFoundation extends BaseFoundation<ModalAdapter> {
64
+ private _debouncedOk;
65
+ private _debouncedCancel;
66
+ private _lastCancelTarget;
67
+ private _lastOkTarget;
64
68
  constructor(adapter: ModalAdapter);
65
69
  destroy(): void;
66
70
  handleCancel(e: any): void;
67
71
  handleOk(e: any): void;
72
+ private _invokeCancel;
73
+ private _invokeOk;
68
74
  beforeShow(): void;
69
75
  afterHide(): void;
70
76
  enabledBodyScroll(): void;
@@ -1,19 +1,51 @@
1
+ import _debounce from "lodash/debounce";
1
2
  import BaseFoundation from '../base/foundation';
2
3
  import isPromise from "../utils/isPromise";
3
4
  export default class ModalFoundation extends BaseFoundation {
4
5
  constructor(adapter) {
5
6
  super(Object.assign({}, adapter));
6
- // afterClose() {
7
- // this._adapter.notifyClose();
8
- // }
7
+ this._debouncedOk = _debounce(e => {
8
+ this._invokeOk(e);
9
+ }, 100, {
10
+ leading: true,
11
+ trailing: false
12
+ });
13
+ this._debouncedCancel = _debounce(e => {
14
+ this._invokeCancel(e);
15
+ }, 100, {
16
+ leading: true,
17
+ trailing: false
18
+ });
19
+ this._lastCancelTarget = null;
20
+ this._lastOkTarget = null;
9
21
  this.toggleDisplayNone = (displayNone, callback) => {
10
22
  this._adapter.toggleDisplayNone(displayNone, callback);
11
23
  };
12
24
  }
13
25
  destroy() {
26
+ this._debouncedOk.cancel();
27
+ this._debouncedCancel.cancel();
14
28
  this.afterHide();
15
29
  }
16
30
  handleCancel(e) {
31
+ var _a, _b;
32
+ const target = (_b = (_a = e === null || e === void 0 ? void 0 : e.currentTarget) !== null && _a !== void 0 ? _a : e === null || e === void 0 ? void 0 : e.target) !== null && _b !== void 0 ? _b : null;
33
+ if (target !== this._lastCancelTarget) {
34
+ this._debouncedCancel.cancel();
35
+ }
36
+ this._lastCancelTarget = target;
37
+ this._debouncedCancel(e);
38
+ }
39
+ handleOk(e) {
40
+ var _a, _b;
41
+ const target = (_b = (_a = e === null || e === void 0 ? void 0 : e.currentTarget) !== null && _a !== void 0 ? _a : e === null || e === void 0 ? void 0 : e.target) !== null && _b !== void 0 ? _b : null;
42
+ if (target !== this._lastOkTarget) {
43
+ this._debouncedOk.cancel();
44
+ }
45
+ this._lastOkTarget = target;
46
+ this._debouncedOk(e);
47
+ }
48
+ _invokeCancel(e) {
17
49
  var _a;
18
50
  const result = this._adapter.notifyCancel(e);
19
51
  if (isPromise(result)) {
@@ -32,7 +64,7 @@ export default class ModalFoundation extends BaseFoundation {
32
64
  });
33
65
  }
34
66
  }
35
- handleOk(e) {
67
+ _invokeOk(e) {
36
68
  var _a;
37
69
  const result = this._adapter.notifyOk(e);
38
70
  if (isPromise(result)) {
@@ -48,7 +48,13 @@ class PaginationFoundation extends BaseFoundation {
48
48
  prevIsDisabled = false;
49
49
  nextIsDisabled = true;
50
50
  }
51
- this._adapter.setDisabled(prevIsDisabled, nextIsDisabled);
51
+ const {
52
+ prevDisabled: currentPrevDisabled,
53
+ nextDisabled: currentNextDisabled
54
+ } = this.getStates();
55
+ if (prevIsDisabled !== currentPrevDisabled || nextIsDisabled !== currentNextDisabled) {
56
+ this._adapter.setDisabled(prevIsDisabled, nextIsDisabled);
57
+ }
52
58
  }
53
59
  goPage(targetPageIndex) {
54
60
  if (targetPageIndex === '...') {
@@ -92,9 +98,17 @@ class PaginationFoundation extends BaseFoundation {
92
98
  total,
93
99
  pageSize
94
100
  });
95
- this._adapter.updateTotal(total);
96
- this._adapter.setCurrentPage(targetPageIndex);
97
- this._adapter.updatePageSize(pageSize);
101
+ // Only call setState when value actually changed to avoid unnecessary re-renders
102
+ // that can cause infinite loops in React 18's concurrent batching
103
+ if (total !== this.getState('total')) {
104
+ this._adapter.updateTotal(total);
105
+ }
106
+ if (targetPageIndex !== this.getState('currentPage')) {
107
+ this._adapter.setCurrentPage(targetPageIndex);
108
+ }
109
+ if (pageSize !== this.getState('pageSize')) {
110
+ this._adapter.updatePageSize(pageSize);
111
+ }
98
112
  }
99
113
  updateAllPageNumbers(total, pageSize) {
100
114
  // only need to update in small size
@@ -230,9 +244,16 @@ class PaginationFoundation extends BaseFoundation {
230
244
  total,
231
245
  currentPage
232
246
  } = this.getStates();
233
- // After converting the switching page capacity, which page is the current page
234
- const currentPageFirstItemIndex = (currentPage - 1) * pageSize + 1;
235
- const newCurrentPage = Math.ceil(currentPageFirstItemIndex / newPageSize);
247
+ // Check if we should prevent page change when pageSize changes
248
+ const {
249
+ preventPageChangeOnPageSizeChange
250
+ } = this.getProps();
251
+ let newCurrentPage = currentPage;
252
+ if (!preventPageChangeOnPageSizeChange) {
253
+ // After converting the switching page capacity, which page is the current page
254
+ const currentPageFirstItemIndex = (currentPage - 1) * pageSize + 1;
255
+ newCurrentPage = Math.ceil(currentPageFirstItemIndex / newPageSize);
256
+ }
236
257
  this.updatePage(newCurrentPage, total, newPageSize);
237
258
  if (currentPage !== newCurrentPage) {
238
259
  this._adapter.notifyPageChange(newCurrentPage);
@@ -3,7 +3,7 @@ export interface PinCodeBaseProps {
3
3
  disabled?: boolean;
4
4
  value?: string;
5
5
  format?: "number" | "mixed" | RegExp | ((value: string) => boolean);
6
- onChange: (value: string) => void;
6
+ onChange?: (value: string) => void;
7
7
  defaultValue?: string;
8
8
  count?: number;
9
9
  autoFocus?: boolean;
@@ -9,7 +9,7 @@
9
9
  .semi-resizable-resizableHandler {
10
10
  position: absolute;
11
11
  user-select: none;
12
- z-index: 2000;
12
+ z-index: 10;
13
13
  }
14
14
  .semi-resizable-resizableHandler-top {
15
15
  width: 100%;
@@ -91,7 +91,7 @@
91
91
  }
92
92
  .semi-resizable-handler {
93
93
  user-select: none;
94
- z-index: 2000;
94
+ z-index: 10;
95
95
  display: flex;
96
96
  align-items: center;
97
97
  justify-content: center;
@@ -114,7 +114,7 @@
114
114
  height: 100%;
115
115
  width: 100%;
116
116
  inset: 0;
117
- z-index: 2010;
117
+ z-index: 20;
118
118
  opacity: 0;
119
119
  position: fixed;
120
120
  }
@@ -1,5 +1,5 @@
1
- $z-resizable_handler: 2000 !default; // 伸缩框组件中handler的z-index
2
- $z-resizable_background: 2010; // 伸缩框组件中背景的z-index
1
+ $z-resizable_handler: 10 !default; // 伸缩框组件中handler的z-index,保持较低层级避免覆盖弹出层组件
2
+ $z-resizable_background: 20; // 伸缩框组件中背景的z-index,保持略高于handler
3
3
 
4
4
  $height-row-handler: 10px; // 单个伸缩框中上下handler的高度
5
5
  $width-col-handler: 10px; // 单个伸缩框中左右handler的宽度
@@ -54,7 +54,7 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
54
54
  constructor(adapter: SelectAdapter);
55
55
  _keydownHandler: (...arg: any[]) => void | null;
56
56
  init(): void;
57
- focus(): void;
57
+ focus(optionsForOpen?: BasicOptionProps[]): void;
58
58
  _focusTrigger(): void;
59
59
  destroy(): void;
60
60
  _setDropdownWidth(): void;
@@ -34,20 +34,31 @@ export default class SelectFoundation extends BaseFoundation {
34
34
  }
35
35
  const autoFocus = this.getProp('autoFocus');
36
36
  if (autoFocus) {
37
- this.focus();
37
+ this.focus(originalOptions);
38
38
  }
39
39
  }
40
- focus() {
40
+ focus(optionsForOpen) {
41
41
  const isFilterable = this._isFilterable();
42
42
  const isMultiple = this._isMultiple();
43
+ const {
44
+ isOpen
45
+ } = this.getStates();
43
46
  this._adapter.updateFocusState(true);
44
47
  this._adapter.setIsFocusInContainer(false);
45
- if (isFilterable && isMultiple) {
46
- // when filter and multiple, only focus input
47
- this.focusInput();
48
- } else if (isFilterable && !isMultiple) {
49
- // when filter and not multiple, only show input and focus input
50
- this.toggle2SearchInput(true);
48
+ if (isFilterable) {
49
+ if (isMultiple) {
50
+ // when filter and multiple, focus input and open dropdown
51
+ this.focusInput();
52
+ if (!isOpen) {
53
+ this.open(undefined, optionsForOpen);
54
+ }
55
+ } else {
56
+ // when filter and not multiple, show input, focus it and open dropdown
57
+ this.toggle2SearchInput(true);
58
+ if (!isOpen) {
59
+ this.open(undefined, optionsForOpen);
60
+ }
61
+ }
51
62
  } else {
52
63
  this._focusTrigger();
53
64
  }
@@ -69,11 +69,17 @@ $basicType: #{$module}-basic;
69
69
 
70
70
  .#{$item}-title {
71
71
  max-width: $width-steps_basic_item_title-maxWidth;
72
+ min-height: $height-steps_basic_item_left-icon;
73
+ display: inline-flex;
74
+ align-items: center;
72
75
 
73
76
  .#{$item}-title-text {
74
77
  @include text-overflow-hidden;
75
- transition: color $transition_duration-steps_item_title-text $transition_function-steps_item_title-text $transition_delay-steps_item_title-text
76
-
78
+ transition: color $transition_duration-steps_item_title-text $transition_function-steps_item_title-text $transition_delay-steps_item_title-text;
79
+
80
+ &-empty {
81
+ width: 0;
82
+ }
77
83
  }
78
84
  }
79
85
 
@@ -193,6 +193,9 @@
193
193
  }
194
194
  .semi-steps-basic.semi-steps-horizontal .semi-steps-item .semi-steps-item-title {
195
195
  max-width: 80%;
196
+ min-height: 24px;
197
+ display: inline-flex;
198
+ align-items: center;
196
199
  }
197
200
  .semi-steps-basic.semi-steps-horizontal .semi-steps-item .semi-steps-item-title .semi-steps-item-title-text {
198
201
  overflow: hidden;
@@ -200,6 +203,9 @@
200
203
  white-space: nowrap;
201
204
  transition: color var(--semi-transition_duration-none) var(--semi-transition_function-easeIn) var(--semi-transition_delay-none);
202
205
  }
206
+ .semi-steps-basic.semi-steps-horizontal .semi-steps-item .semi-steps-item-title .semi-steps-item-title-text-empty {
207
+ width: 0;
208
+ }
203
209
  .semi-steps-basic.semi-steps-vertical {
204
210
  display: flex;
205
211
  flex-flow: column nowrap;
@@ -74,8 +74,10 @@ export interface UploadAdapter<P = Record<string, any>, S = Record<string, any>>
74
74
  notifyPreviewClick: (file: any) => void;
75
75
  notifyDrop: (e: any, files: Array<File>, fileList: Array<BaseFileItem>) => void;
76
76
  notifyAcceptInvalid: (invalidFiles: Array<File>) => void;
77
- registerPastingHandler: (cb?: (params?: any) => void) => void;
77
+ registerPastingHandler: (cb?: (params?: KeyboardEvent | ClipboardEvent) => void) => void;
78
78
  unRegisterPastingHandler: () => void;
79
+ registerPasteEventHandler: (cb?: (params?: ClipboardEvent) => void) => void;
80
+ unRegisterPasteEventHandler: () => void;
79
81
  isMac: () => boolean;
80
82
  notifyPastingError: (error: Error | PermissionStatus) => void;
81
83
  }
@@ -87,6 +89,11 @@ declare class UploadFoundation<P = Record<string, any>, S = Record<string, any>>
87
89
  * when _createURL is called multiple times in a sync loop.
88
90
  */
89
91
  _localUrls: Record<string, string>;
92
+ /**
93
+ * Flag to prevent duplicate handling of paste events.
94
+ * When paste event is successfully handled, we ignore the subsequent keydown event.
95
+ */
96
+ _pasteHandled: boolean;
90
97
  constructor(adapter: UploadAdapter<P, S>);
91
98
  init(): void;
92
99
  /**