@douyinfe/semi-foundation 2.93.0 → 2.94.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
@@ -50,6 +50,11 @@ class UploadFoundation extends BaseFoundation {
50
50
  * when _createURL is called multiple times in a sync loop.
51
51
  */
52
52
  this._localUrls = {};
53
+ /**
54
+ * Flag to prevent duplicate handling of paste events.
55
+ * When paste event is successfully handled, we ignore the subsequent keydown event.
56
+ */
57
+ this._pasteHandled = false;
53
58
  }
54
59
  init() {
55
60
  // make sure state reset, otherwise may cause upload abort in React StrictMode, like https://github.com/DouyinFE/semi-design/pull/843
@@ -1074,40 +1079,83 @@ class UploadFoundation extends BaseFoundation {
1074
1079
  }
1075
1080
  }
1076
1081
  handlePasting(e) {
1077
- const isMac = this._adapter.isMac();
1078
- const isCombineKeydown = isMac ? e.metaKey : e.ctrlKey;
1079
1082
  const {
1080
1083
  addOnPasting
1081
1084
  } = this.getProps();
1082
- if (addOnPasting) {
1083
- if (isCombineKeydown && e.code === 'KeyV') {
1084
- // https://github.com/microsoft/TypeScript/issues/33923
1085
- const permissionName = 'clipboard-read';
1086
- // The main thread should not be blocked by clipboard, so callback writing is required here. No await here
1087
- navigator.permissions.query({
1088
- name: permissionName
1089
- }).then(result => {
1090
- if (result.state === 'granted' || result.state === 'prompt') {
1091
- // user has authorized or will authorize
1092
- navigator.clipboard.read().then(clipboardItems => {
1093
- // Process the data read from the pasteboard
1094
- // Check the returned data type to determine if it is image data, and process accordingly
1095
- this.readFileFromClipboard(clipboardItems);
1096
- });
1097
- } else {
1098
- this._adapter.notifyPastingError(result);
1085
+ if (!addOnPasting) {
1086
+ return;
1087
+ }
1088
+ // Try to read from native paste event (clipboardData) first as fallback
1089
+ if (e.type === 'paste' && e.clipboardData && e.clipboardData.items) {
1090
+ const items = e.clipboardData.items;
1091
+ const files = [];
1092
+ for (let i = 0; i < items.length; i++) {
1093
+ const item = items[i];
1094
+ // Check if the item is a file (image, etc.)
1095
+ if (item.kind === 'file') {
1096
+ const file = item.getAsFile();
1097
+ if (file) {
1098
+ files.push(file);
1099
1099
  }
1100
- }).catch(error => {
1101
- this._adapter.notifyPastingError(error);
1102
- });
1100
+ }
1101
+ }
1102
+ if (files.length > 0) {
1103
+ e.preventDefault();
1104
+ this.handleChange(files);
1105
+ // Mark that paste event has been handled to prevent duplicate handling by keydown event
1106
+ this._pasteHandled = true;
1107
+ // Reset the flag after a short delay to allow future paste operations
1108
+ setTimeout(() => {
1109
+ this._pasteHandled = false;
1110
+ }, 100);
1111
+ return;
1103
1112
  }
1104
1113
  }
1114
+ // Fallback to navigator.clipboard for keyboard events (keydown with Ctrl/Cmd+V)
1115
+ // Skip if paste event has already been handled
1116
+ if (this._pasteHandled) {
1117
+ this._pasteHandled = false;
1118
+ return;
1119
+ }
1120
+ const isMac = this._adapter.isMac();
1121
+ const isCombineKeydown = isMac ? e.metaKey : e.ctrlKey;
1122
+ if (isCombineKeydown && e.code === 'KeyV') {
1123
+ // Check if navigator.clipboard is available
1124
+ if (!navigator.clipboard || typeof navigator.clipboard.read !== 'function') {
1125
+ return;
1126
+ }
1127
+ // https://github.com/microsoft/TypeScript/issues/33923
1128
+ const permissionName = 'clipboard-read';
1129
+ // The main thread should not be blocked by clipboard, so callback writing is required here. No await here
1130
+ navigator.permissions.query({
1131
+ name: permissionName
1132
+ }).then(result => {
1133
+ if (result.state === 'granted' || result.state === 'prompt') {
1134
+ // user has authorized or will authorize
1135
+ navigator.clipboard.read().then(clipboardItems => {
1136
+ // Process the data read from the pasteboard
1137
+ // Check the returned data type to determine if it is image data, and process accordingly
1138
+ this.readFileFromClipboard(clipboardItems);
1139
+ }).catch(error => {
1140
+ this._adapter.notifyPastingError(error);
1141
+ });
1142
+ } else {
1143
+ this._adapter.notifyPastingError(result);
1144
+ }
1145
+ }).catch(error => {
1146
+ this._adapter.notifyPastingError(error);
1147
+ });
1148
+ }
1105
1149
  }
1106
1150
  bindPastingHandler() {
1151
+ // Register keyboard event handler (keydown with Ctrl/Cmd+V)
1107
1152
  this._adapter.registerPastingHandler(event => this.handlePasting(event));
1153
+ // Register native paste event handler as fallback
1154
+ this._adapter.registerPasteEventHandler(event => this.handlePasting(event));
1108
1155
  }
1109
1156
  unbindPastingHandler() {
1110
1157
  this._adapter.unRegisterPastingHandler();
1158
+ this._adapter.unRegisterPasteEventHandler();
1111
1159
  }
1112
1160
  }
1113
1161
  export default UploadFoundation;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Escape HTML angle brackets in markdown text, preserving code blocks and inline code.
3
+ *
4
+ * In `format='md'` mode, @mdx-js/mdx uses `rehypeRemoveRaw` which strips all raw HTML nodes.
5
+ * This causes user-typed HTML-like content (e.g. `<AgentChat />`) to silently disappear.
6
+ * By escaping `<` to `&lt;` outside of code spans/blocks, the markdown parser treats them
7
+ * as literal text instead of HTML tags.
8
+ */
9
+ export declare function escapeHtmlInMarkdown(text: string): string;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Escape HTML angle brackets in markdown text, preserving code blocks and inline code.
3
+ *
4
+ * In `format='md'` mode, @mdx-js/mdx uses `rehypeRemoveRaw` which strips all raw HTML nodes.
5
+ * This causes user-typed HTML-like content (e.g. `<AgentChat />`) to silently disappear.
6
+ * By escaping `<` to `&lt;` outside of code spans/blocks, the markdown parser treats them
7
+ * as literal text instead of HTML tags.
8
+ */
9
+ export function escapeHtmlInMarkdown(text) {
10
+ const lines = text.split('\n');
11
+ const result = [];
12
+ let fenceChar = null;
13
+ let fenceLen = 0;
14
+ for (let i = 0; i < lines.length; i++) {
15
+ const line = lines[i];
16
+ if (fenceChar !== null) {
17
+ // Inside a fenced code block — check for closing fence
18
+ result.push(line);
19
+ const trimmed = line.trimEnd();
20
+ if (trimmed.length >= fenceLen && trimmed[0] === fenceChar && trimmed === fenceChar.repeat(trimmed.length)) {
21
+ fenceChar = null;
22
+ }
23
+ } else {
24
+ // Check if this line opens a fenced code block
25
+ const fenceMatch = line.match(/^(`{3,}|~{3,})/);
26
+ if (fenceMatch) {
27
+ fenceChar = fenceMatch[1][0];
28
+ fenceLen = fenceMatch[1].length;
29
+ result.push(line);
30
+ } else {
31
+ result.push(escapeAngleBracketsOutsideInlineCode(line));
32
+ }
33
+ }
34
+ }
35
+ return result.join('\n');
36
+ }
37
+ /**
38
+ * Escape `<` to `&lt;` in a single line, but preserve content inside inline code spans.
39
+ */
40
+ function escapeAngleBracketsOutsideInlineCode(line) {
41
+ const parts = [];
42
+ let i = 0;
43
+ while (i < line.length) {
44
+ if (line[i] === '`') {
45
+ // Count opening backticks
46
+ let count = 0;
47
+ const start = i;
48
+ while (i < line.length && line[i] === '`') {
49
+ count++;
50
+ i++;
51
+ }
52
+ // Find matching closing backticks (exact same count)
53
+ const closer = '`'.repeat(count);
54
+ const closeIdx = line.indexOf(closer, i);
55
+ if (closeIdx !== -1) {
56
+ parts.push(line.slice(start, closeIdx + count));
57
+ i = closeIdx + count;
58
+ } else {
59
+ // No matching close — treat backticks as regular text, escape any `<`
60
+ parts.push(line.slice(start, i).replace(/</g, '&lt;'));
61
+ }
62
+ } else if (line[i] === '<') {
63
+ parts.push('&lt;');
64
+ i++;
65
+ } else {
66
+ // Collect a run of non-special characters at once
67
+ const next = line.indexOf('<', i);
68
+ const nextBt = line.indexOf('`', i);
69
+ let end;
70
+ if (next === -1 && nextBt === -1) {
71
+ end = line.length;
72
+ } else if (next === -1) {
73
+ end = nextBt;
74
+ } else if (nextBt === -1) {
75
+ end = next;
76
+ } else {
77
+ end = Math.min(next, nextBt);
78
+ }
79
+ parts.push(line.slice(i, end));
80
+ i = end;
81
+ }
82
+ }
83
+ return parts.join('');
84
+ }
@@ -52,7 +52,9 @@ function cleanup(obj, path) {
52
52
  // lodashRemove(target, (value, index, array) => index > lastIndex);
53
53
  // }
54
54
  // Delete object if its empty
55
- if (Array.isArray(target) && target.every(e => e == null)) {
55
+ // Only delete array if it's not empty AND all elements are null/undefined
56
+ // This prevents empty arrays from being deleted (issue #2834)
57
+ if (Array.isArray(target) && target.length > 0 && target.every(e => e == null)) {
56
58
  _unset(obj, path);
57
59
  } else if (isEmptyObject(target)) {
58
60
  _unset(obj, path);
@@ -1,5 +1,6 @@
1
1
  import BaseFoundation, { DefaultAdapter } from '../base/foundation';
2
2
  import isPromise from "../utils/isPromise";
3
+ import { debounce } from 'lodash';
3
4
 
4
5
  export type OKType = 'primary' | 'secondary' | 'tertiary' | 'warning' | 'danger';
5
6
  export type Size = 'small' | 'medium' | 'large' | 'full-width';
@@ -67,6 +68,17 @@ export interface ModalState {
67
68
 
68
69
  export default class ModalFoundation extends BaseFoundation<ModalAdapter> {
69
70
 
71
+ private _debouncedOk = debounce((e: any) => {
72
+ this._invokeOk(e);
73
+ }, 100, { leading: true, trailing: false });
74
+
75
+ private _debouncedCancel = debounce((e: any) => {
76
+ this._invokeCancel(e);
77
+ }, 100, { leading: true, trailing: false });
78
+
79
+ private _lastCancelTarget: EventTarget | null = null;
80
+ private _lastOkTarget: EventTarget | null = null;
81
+
70
82
  constructor(adapter: ModalAdapter) {
71
83
  super({
72
84
  ...adapter,
@@ -74,10 +86,30 @@ export default class ModalFoundation extends BaseFoundation<ModalAdapter> {
74
86
  }
75
87
 
76
88
  destroy() {
89
+ this._debouncedOk.cancel();
90
+ this._debouncedCancel.cancel();
77
91
  this.afterHide();
78
92
  }
79
93
 
80
94
  handleCancel(e: any) {
95
+ const target = e?.currentTarget ?? e?.target ?? null;
96
+ if (target !== this._lastCancelTarget) {
97
+ this._debouncedCancel.cancel();
98
+ }
99
+ this._lastCancelTarget = target;
100
+ this._debouncedCancel(e);
101
+ }
102
+
103
+ handleOk(e: any) {
104
+ const target = e?.currentTarget ?? e?.target ?? null;
105
+ if (target !== this._lastOkTarget) {
106
+ this._debouncedOk.cancel();
107
+ }
108
+ this._lastOkTarget = target;
109
+ this._debouncedOk(e);
110
+ }
111
+
112
+ private _invokeCancel(e: any) {
81
113
  const result = this._adapter.notifyCancel(e);
82
114
  if (isPromise(result)) {
83
115
  this._adapter.setState({ onCancelReturnPromiseStatus: "pending" });
@@ -90,7 +122,7 @@ export default class ModalFoundation extends BaseFoundation<ModalAdapter> {
90
122
  }
91
123
  }
92
124
 
93
- handleOk(e: any) {
125
+ private _invokeOk(e: any) {
94
126
  const result = this._adapter.notifyOk(e);
95
127
  if (isPromise(result)) {
96
128
  this._adapter.setState({ onOKReturnPromiseStatus: "pending" });
@@ -116,38 +148,7 @@ export default class ModalFoundation extends BaseFoundation<ModalAdapter> {
116
148
  this._adapter.enabledBodyScroll();
117
149
  }
118
150
 
119
- // afterClose() {
120
- // this._adapter.notifyClose();
121
- // }
122
-
123
-
124
151
  toggleDisplayNone = (displayNone: boolean, callback?: (displayNone: boolean) => void) => {
125
152
  this._adapter.toggleDisplayNone(displayNone, callback);
126
153
  };
127
-
128
-
129
- // mergeMotionProp = (motion: Motion, prop: string, cb: () => void) => {
130
- // const mergedMotion = typeof (motion) === 'undefined' || motion ? {
131
- // ...(motion as { [key: string]: (() => void) | boolean }),
132
- // [prop]: (...args: any) => {
133
- // const curr = get(motion, prop);
134
- // if (typeof curr === 'function') {
135
- // curr(...args);
136
- // }
137
- // cb();
138
- // }
139
- // } : false;
140
- // return mergedMotion;
141
- // };
142
- //
143
- // getMergedMotion() {
144
- // let { motion } = this._adapter.getProps();
145
- // const { keepDOM } = this._adapter.getProps();
146
- // motion = this.mergeMotionProp(motion, 'didLeave', this.afterClose.bind(this));
147
- // if (!keepDOM) {
148
- // return motion;
149
- // }
150
- // const mergedMotion = this.mergeMotionProp(motion, 'didLeave', this.toggleHidden.bind(this, true));
151
- // return mergedMotion;
152
- // }
153
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@douyinfe/semi-foundation",
3
- "version": "2.93.0",
3
+ "version": "2.94.1",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "clean": "rimraf lib",
@@ -13278,6 +13278,36 @@
13278
13278
  "import": "./lib/es/utils/dom.js",
13279
13279
  "require": "./lib/cjs/utils/dom.js"
13280
13280
  },
13281
+ "./lib/es/utils/escapeHtml.js": {
13282
+ "types": "./lib/es/utils/escapeHtml.d.ts",
13283
+ "import": "./lib/es/utils/escapeHtml.js",
13284
+ "require": "./lib/cjs/utils/escapeHtml.js"
13285
+ },
13286
+ "./lib/es/utils/escapeHtml": {
13287
+ "types": "./lib/es/utils/escapeHtml.d.ts",
13288
+ "import": "./lib/es/utils/escapeHtml.js",
13289
+ "require": "./lib/cjs/utils/escapeHtml.js"
13290
+ },
13291
+ "./lib/cjs/utils/escapeHtml.js": {
13292
+ "types": "./lib/es/utils/escapeHtml.d.ts",
13293
+ "import": "./lib/es/utils/escapeHtml.js",
13294
+ "require": "./lib/cjs/utils/escapeHtml.js"
13295
+ },
13296
+ "./lib/cjs/utils/escapeHtml": {
13297
+ "types": "./lib/es/utils/escapeHtml.d.ts",
13298
+ "import": "./lib/es/utils/escapeHtml.js",
13299
+ "require": "./lib/cjs/utils/escapeHtml.js"
13300
+ },
13301
+ "./utils/escapeHtml.js": {
13302
+ "types": "./lib/es/utils/escapeHtml.d.ts",
13303
+ "import": "./lib/es/utils/escapeHtml.js",
13304
+ "require": "./lib/cjs/utils/escapeHtml.js"
13305
+ },
13306
+ "./utils/escapeHtml": {
13307
+ "types": "./lib/es/utils/escapeHtml.d.ts",
13308
+ "import": "./lib/es/utils/escapeHtml.js",
13309
+ "require": "./lib/cjs/utils/escapeHtml.js"
13310
+ },
13281
13311
  "./lib/es/utils/function.js": {
13282
13312
  "types": "./lib/es/utils/function.d.ts",
13283
13313
  "import": "./lib/es/utils/function.js",
@@ -14180,8 +14210,8 @@
14180
14210
  }
14181
14211
  },
14182
14212
  "dependencies": {
14183
- "@douyinfe/semi-animation": "2.93.0",
14184
- "@douyinfe/semi-json-viewer-core": "2.93.0",
14213
+ "@douyinfe/semi-animation": "2.94.1",
14214
+ "@douyinfe/semi-json-viewer-core": "2.94.1",
14185
14215
  "@mdx-js/mdx": "^3.0.1",
14186
14216
  "async-validator": "^3.5.0",
14187
14217
  "classnames": "^2.2.6",
@@ -14189,7 +14219,7 @@
14189
14219
  "date-fns-tz": "^1.3.8",
14190
14220
  "fast-copy": "^3.0.1 ",
14191
14221
  "lodash": "^4.17.21",
14192
- "lottie-web": "^5.12.2",
14222
+ "lottie-web": "^5.13.0",
14193
14223
  "memoize-one": "^5.2.1",
14194
14224
  "prismjs": "^1.29.0",
14195
14225
  "remark-gfm": "^4.0.0",
@@ -14202,7 +14232,7 @@
14202
14232
  "*.scss",
14203
14233
  "*.css"
14204
14234
  ],
14205
- "gitHead": "e1959fe97f095b4b92f9a6c9a96afd83f2b60487",
14235
+ "gitHead": "9d324c236709af72bc2b18166bcc738b3d7f9d91",
14206
14236
  "devDependencies": {
14207
14237
  "@babel/plugin-transform-runtime": "^7.15.8",
14208
14238
  "@babel/preset-env": "^7.15.8",
@@ -64,7 +64,10 @@ class PaginationFoundation<P = Record<string, any>, S = Record<string, any>> ext
64
64
  prevIsDisabled = false;
65
65
  nextIsDisabled = true;
66
66
  }
67
- this._adapter.setDisabled(prevIsDisabled, nextIsDisabled);
67
+ const { prevDisabled: currentPrevDisabled, nextDisabled: currentNextDisabled } = this.getStates();
68
+ if (prevIsDisabled !== currentPrevDisabled || nextIsDisabled !== currentNextDisabled) {
69
+ this._adapter.setDisabled(prevIsDisabled, nextIsDisabled);
70
+ }
68
71
  }
69
72
 
70
73
  goPage(targetPageIndex: number | '...') {
@@ -98,9 +101,17 @@ class PaginationFoundation<P = Record<string, any>, S = Record<string, any>> ext
98
101
  }
99
102
  this._updateDisabled({ currentPage: targetPageIndex, total, pageSize });
100
103
  this._updatePageList({ currentPage: targetPageIndex, total, pageSize });
101
- this._adapter.updateTotal(total);
102
- this._adapter.setCurrentPage(targetPageIndex);
103
- this._adapter.updatePageSize(pageSize);
104
+ // Only call setState when value actually changed to avoid unnecessary re-renders
105
+ // that can cause infinite loops in React 18's concurrent batching
106
+ if (total !== this.getState('total')) {
107
+ this._adapter.updateTotal(total);
108
+ }
109
+ if (targetPageIndex !== this.getState('currentPage')) {
110
+ this._adapter.setCurrentPage(targetPageIndex);
111
+ }
112
+ if (pageSize !== this.getState('pageSize')) {
113
+ this._adapter.updatePageSize(pageSize);
114
+ }
104
115
  }
105
116
 
106
117
  updateAllPageNumbers(total: number, pageSize: number) {
@@ -203,9 +214,16 @@ class PaginationFoundation<P = Record<string, any>, S = Record<string, any>> ext
203
214
  this._adapter.notifyPageSizeChange(newPageSize);
204
215
  const { total, currentPage } = this.getStates();
205
216
 
206
- // After converting the switching page capacity, which page is the current page
207
- const currentPageFirstItemIndex = (currentPage - 1) * pageSize + 1;
208
- const newCurrentPage = Math.ceil(currentPageFirstItemIndex / newPageSize);
217
+ // Check if we should prevent page change when pageSize changes
218
+ const { preventPageChangeOnPageSizeChange } = this.getProps();
219
+
220
+ let newCurrentPage = currentPage;
221
+ if (!preventPageChangeOnPageSizeChange) {
222
+ // After converting the switching page capacity, which page is the current page
223
+ const currentPageFirstItemIndex = (currentPage - 1) * pageSize + 1;
224
+ newCurrentPage = Math.ceil(currentPageFirstItemIndex / newPageSize);
225
+ }
226
+
209
227
  this.updatePage(newCurrentPage, total, newPageSize);
210
228
  if (currentPage !== newCurrentPage) {
211
229
  this._adapter.notifyPageChange(newCurrentPage);
@@ -5,7 +5,7 @@ export interface PinCodeBaseProps {
5
5
  disabled?: boolean;
6
6
  value?: string;
7
7
  format?: "number" | "mixed" | RegExp | ((value: string) => boolean);
8
- onChange: (value: string) => void;
8
+ onChange?: (value: string) => void;
9
9
  defaultValue?: string;
10
10
  count?: number;
11
11
  autoFocus?: boolean;
@@ -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的宽度
@@ -81,21 +81,32 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
81
81
 
82
82
  const autoFocus = this.getProp('autoFocus');
83
83
  if (autoFocus) {
84
- this.focus();
84
+ this.focus(originalOptions);
85
85
  }
86
86
  }
87
87
 
88
- focus() {
88
+ focus(optionsForOpen?: BasicOptionProps[]) {
89
89
  const isFilterable = this._isFilterable();
90
90
  const isMultiple = this._isMultiple();
91
+ const { isOpen } = this.getStates();
92
+
91
93
  this._adapter.updateFocusState(true);
92
94
  this._adapter.setIsFocusInContainer(false);
93
- if (isFilterable && isMultiple) {
94
- // when filter and multiple, only focus input
95
- this.focusInput();
96
- } else if (isFilterable && !isMultiple) {
97
- // when filter and not multiple, only show input and focus input
98
- this.toggle2SearchInput(true);
95
+
96
+ if (isFilterable) {
97
+ if (isMultiple) {
98
+ // when filter and multiple, focus input and open dropdown
99
+ this.focusInput();
100
+ if (!isOpen) {
101
+ this.open(undefined, optionsForOpen);
102
+ }
103
+ } else {
104
+ // when filter and not multiple, show input, focus it and open dropdown
105
+ this.toggle2SearchInput(true);
106
+ if (!isOpen) {
107
+ this.open(undefined, optionsForOpen);
108
+ }
109
+ }
99
110
  } else {
100
111
  this._focusTrigger();
101
112
  }
@@ -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