@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
@@ -88,8 +88,10 @@ export interface UploadAdapter<P = Record<string, any>, S = Record<string, any>>
88
88
  notifyPreviewClick: (file: any) => void;
89
89
  notifyDrop: (e: any, files: Array<File>, fileList: Array<BaseFileItem>) => void;
90
90
  notifyAcceptInvalid: (invalidFiles: Array<File>) => void;
91
- registerPastingHandler: (cb?: (params?: any) => void) => void;
91
+ registerPastingHandler: (cb?: (params?: KeyboardEvent | ClipboardEvent) => void) => void;
92
92
  unRegisterPastingHandler: () => void;
93
+ registerPasteEventHandler: (cb?: (params?: ClipboardEvent) => void) => void;
94
+ unRegisterPasteEventHandler: () => void;
93
95
  isMac: () => boolean;
94
96
  notifyPastingError: (error: Error | PermissionStatus) => void
95
97
  // notifyPasting: () => void;
@@ -103,6 +105,11 @@ class UploadFoundation<P = Record<string, any>, S = Record<string, any>> extends
103
105
  * when _createURL is called multiple times in a sync loop.
104
106
  */
105
107
  _localUrls: Record<string, string> = {};
108
+ /**
109
+ * Flag to prevent duplicate handling of paste events.
110
+ * When paste event is successfully handled, we ignore the subsequent keydown event.
111
+ */
112
+ _pasteHandled: boolean = false;
106
113
  constructor(adapter: UploadAdapter<P, S>) {
107
114
  super({ ...adapter });
108
115
  }
@@ -1024,41 +1031,91 @@ class UploadFoundation<P = Record<string, any>, S = Record<string, any>> extends
1024
1031
  }
1025
1032
 
1026
1033
  handlePasting(e: any) {
1034
+ const { addOnPasting } = this.getProps();
1035
+ if (!addOnPasting) {
1036
+ return;
1037
+ }
1038
+
1039
+ // Try to read from native paste event (clipboardData) first as fallback
1040
+ if (e.type === 'paste' && e.clipboardData && e.clipboardData.items) {
1041
+ const items = e.clipboardData.items;
1042
+ const files: File[] = [];
1043
+
1044
+ for (let i = 0; i < items.length; i++) {
1045
+ const item = items[i];
1046
+ // Check if the item is a file (image, etc.)
1047
+ if (item.kind === 'file') {
1048
+ const file = item.getAsFile();
1049
+ if (file) {
1050
+ files.push(file);
1051
+ }
1052
+ }
1053
+ }
1054
+
1055
+ if (files.length > 0) {
1056
+ e.preventDefault();
1057
+ this.handleChange(files);
1058
+ // Mark that paste event has been handled to prevent duplicate handling by keydown event
1059
+ this._pasteHandled = true;
1060
+ // Reset the flag after a short delay to allow future paste operations
1061
+ setTimeout(() => {
1062
+ this._pasteHandled = false;
1063
+ }, 100);
1064
+ return;
1065
+ }
1066
+ }
1067
+
1068
+ // Fallback to navigator.clipboard for keyboard events (keydown with Ctrl/Cmd+V)
1069
+ // Skip if paste event has already been handled
1070
+ if (this._pasteHandled) {
1071
+ this._pasteHandled = false;
1072
+ return;
1073
+ }
1074
+
1027
1075
  const isMac = this._adapter.isMac();
1028
1076
  const isCombineKeydown = isMac ? e.metaKey : e.ctrlKey;
1029
- const { addOnPasting } = this.getProps();
1030
- if (addOnPasting) {
1031
- if (isCombineKeydown && e.code === 'KeyV') {
1032
- // https://github.com/microsoft/TypeScript/issues/33923
1033
- const permissionName = 'clipboard-read' as PermissionName;
1034
- // The main thread should not be blocked by clipboard, so callback writing is required here. No await here
1035
- navigator.permissions
1036
- .query({ name: permissionName })
1037
- .then(result => {
1038
- if (result.state === 'granted' || result.state === 'prompt') {
1039
- // user has authorized or will authorize
1040
- navigator.clipboard.read().then(clipboardItems => {
1041
- // Process the data read from the pasteboard
1042
- // Check the returned data type to determine if it is image data, and process accordingly
1043
- this.readFileFromClipboard(clipboardItems);
1044
- });
1045
- } else {
1046
- this._adapter.notifyPastingError(result);
1047
- }
1048
- })
1049
- .catch(error => {
1050
- this._adapter.notifyPastingError(error);
1051
- });
1077
+
1078
+ if (isCombineKeydown && e.code === 'KeyV') {
1079
+ // Check if navigator.clipboard is available
1080
+ if (!navigator.clipboard || typeof navigator.clipboard.read !== 'function') {
1081
+ return;
1052
1082
  }
1083
+
1084
+ // https://github.com/microsoft/TypeScript/issues/33923
1085
+ const permissionName = 'clipboard-read' as PermissionName;
1086
+ // The main thread should not be blocked by clipboard, so callback writing is required here. No await here
1087
+ navigator.permissions
1088
+ .query({ 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
+ }).catch(error => {
1097
+ this._adapter.notifyPastingError(error);
1098
+ });
1099
+ } else {
1100
+ this._adapter.notifyPastingError(result);
1101
+ }
1102
+ })
1103
+ .catch(error => {
1104
+ this._adapter.notifyPastingError(error);
1105
+ });
1053
1106
  }
1054
1107
  }
1055
1108
 
1056
1109
  bindPastingHandler(): void {
1110
+ // Register keyboard event handler (keydown with Ctrl/Cmd+V)
1057
1111
  this._adapter.registerPastingHandler((event) => this.handlePasting(event));
1112
+ // Register native paste event handler as fallback
1113
+ this._adapter.registerPasteEventHandler((event) => this.handlePasting(event));
1058
1114
  }
1059
1115
 
1060
1116
  unbindPastingHandler() {
1061
1117
  this._adapter.unRegisterPastingHandler();
1118
+ this._adapter.unRegisterPasteEventHandler();
1062
1119
  }
1063
1120
  }
1064
1121
 
@@ -0,0 +1,94 @@
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: string): string {
10
+ const lines = text.split('\n');
11
+ const result: string[] = [];
12
+ let fenceChar: string | null = null;
13
+ let fenceLen = 0;
14
+
15
+ for (let i = 0; i < lines.length; i++) {
16
+ const line = lines[i];
17
+
18
+ if (fenceChar !== null) {
19
+ // Inside a fenced code block — check for closing fence
20
+ result.push(line);
21
+ const trimmed = line.trimEnd();
22
+ if (
23
+ trimmed.length >= fenceLen &&
24
+ trimmed[0] === fenceChar &&
25
+ trimmed === fenceChar.repeat(trimmed.length)
26
+ ) {
27
+ fenceChar = null;
28
+ }
29
+ } else {
30
+ // Check if this line opens a fenced code block
31
+ const fenceMatch = line.match(/^(`{3,}|~{3,})/);
32
+ if (fenceMatch) {
33
+ fenceChar = fenceMatch[1][0];
34
+ fenceLen = fenceMatch[1].length;
35
+ result.push(line);
36
+ } else {
37
+ result.push(escapeAngleBracketsOutsideInlineCode(line));
38
+ }
39
+ }
40
+ }
41
+
42
+ return result.join('\n');
43
+ }
44
+
45
+ /**
46
+ * Escape `<` to `&lt;` in a single line, but preserve content inside inline code spans.
47
+ */
48
+ function escapeAngleBracketsOutsideInlineCode(line: string): string {
49
+ const parts: string[] = [];
50
+ let i = 0;
51
+
52
+ while (i < line.length) {
53
+ if (line[i] === '`') {
54
+ // Count opening backticks
55
+ let count = 0;
56
+ const start = i;
57
+ while (i < line.length && line[i] === '`') {
58
+ count++;
59
+ i++;
60
+ }
61
+ // Find matching closing backticks (exact same count)
62
+ const closer = '`'.repeat(count);
63
+ const closeIdx = line.indexOf(closer, i);
64
+ if (closeIdx !== -1) {
65
+ parts.push(line.slice(start, closeIdx + count));
66
+ i = closeIdx + count;
67
+ } else {
68
+ // No matching close — treat backticks as regular text, escape any `<`
69
+ parts.push(line.slice(start, i).replace(/</g, '&lt;'));
70
+ }
71
+ } else if (line[i] === '<') {
72
+ parts.push('&lt;');
73
+ i++;
74
+ } else {
75
+ // Collect a run of non-special characters at once
76
+ const next = line.indexOf('<', i);
77
+ const nextBt = line.indexOf('`', i);
78
+ let end: number;
79
+ if (next === -1 && nextBt === -1) {
80
+ end = line.length;
81
+ } else if (next === -1) {
82
+ end = nextBt;
83
+ } else if (nextBt === -1) {
84
+ end = next;
85
+ } else {
86
+ end = Math.min(next, nextBt);
87
+ }
88
+ parts.push(line.slice(i, end));
89
+ i = end;
90
+ }
91
+ }
92
+
93
+ return parts.join('');
94
+ }
package/utils/object.ts CHANGED
@@ -66,7 +66,9 @@ function cleanup(obj: ObjectType, path: string[], pull = true) {
66
66
  // }
67
67
 
68
68
  // Delete object if its empty
69
- if (Array.isArray(target) && target.every(e => e == null)) {
69
+ // Only delete array if it's not empty AND all elements are null/undefined
70
+ // This prevents empty arrays from being deleted (issue #2834)
71
+ if (Array.isArray(target) && target.length > 0 && target.every(e => e == null)) {
70
72
  lodashUnset(obj, path);
71
73
  } else if (isEmptyObject(target)) {
72
74
  lodashUnset(obj, path);