@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.
- package/aiChatInput/foundation.ts +3 -1
- package/autoComplete/foundation.ts +3 -2
- package/cascader/foundation.ts +8 -3
- package/collapsible/foundation.ts +1 -0
- package/datePicker/datePicker.scss +2 -2
- package/descriptions/foundation.ts +3 -1
- package/form/foundation.ts +61 -29
- package/form/interface.ts +9 -2
- package/input/textareaFoundation.ts +34 -1
- package/lib/cjs/aiChatInput/foundation.js +3 -1
- package/lib/cjs/autoComplete/foundation.d.ts +1 -0
- package/lib/cjs/autoComplete/foundation.js +1 -1
- package/lib/cjs/cascader/foundation.d.ts +1 -0
- package/lib/cjs/cascader/foundation.js +8 -3
- package/lib/cjs/collapsible/foundation.d.ts +1 -0
- package/lib/cjs/datePicker/datePicker.css +2 -2
- package/lib/cjs/datePicker/datePicker.scss +2 -2
- package/lib/cjs/descriptions/foundation.js +3 -1
- package/lib/cjs/form/foundation.d.ts +5 -5
- package/lib/cjs/form/foundation.js +58 -21
- package/lib/cjs/form/interface.d.ts +8 -2
- package/lib/cjs/input/textareaFoundation.d.ts +12 -0
- package/lib/cjs/input/textareaFoundation.js +39 -0
- package/lib/cjs/modal/modalFoundation.d.ts +6 -0
- package/lib/cjs/modal/modalFoundation.js +36 -4
- package/lib/cjs/pagination/foundation.js +28 -7
- package/lib/cjs/pincode/foundation.d.ts +1 -1
- package/lib/cjs/resizable/resizable.css +3 -3
- package/lib/cjs/resizable/variables.scss +2 -2
- package/lib/cjs/select/foundation.d.ts +1 -1
- package/lib/cjs/select/foundation.js +19 -8
- package/lib/cjs/steps/bacisSteps.scss +8 -2
- package/lib/cjs/steps/steps.css +6 -0
- package/lib/cjs/upload/foundation.d.ts +8 -1
- package/lib/cjs/upload/foundation.js +70 -22
- package/lib/cjs/utils/escapeHtml.d.ts +9 -0
- package/lib/cjs/utils/escapeHtml.js +90 -0
- package/lib/cjs/utils/object.js +3 -1
- package/lib/es/aiChatInput/foundation.js +3 -1
- package/lib/es/autoComplete/foundation.d.ts +1 -0
- package/lib/es/autoComplete/foundation.js +1 -1
- package/lib/es/cascader/foundation.d.ts +1 -0
- package/lib/es/cascader/foundation.js +8 -3
- package/lib/es/collapsible/foundation.d.ts +1 -0
- package/lib/es/datePicker/datePicker.css +2 -2
- package/lib/es/datePicker/datePicker.scss +2 -2
- package/lib/es/descriptions/foundation.js +3 -1
- package/lib/es/form/foundation.d.ts +5 -5
- package/lib/es/form/foundation.js +58 -21
- package/lib/es/form/interface.d.ts +8 -2
- package/lib/es/input/textareaFoundation.d.ts +12 -0
- package/lib/es/input/textareaFoundation.js +39 -0
- package/lib/es/modal/modalFoundation.d.ts +6 -0
- package/lib/es/modal/modalFoundation.js +36 -4
- package/lib/es/pagination/foundation.js +28 -7
- package/lib/es/pincode/foundation.d.ts +1 -1
- package/lib/es/resizable/resizable.css +3 -3
- package/lib/es/resizable/variables.scss +2 -2
- package/lib/es/select/foundation.d.ts +1 -1
- package/lib/es/select/foundation.js +19 -8
- package/lib/es/steps/bacisSteps.scss +8 -2
- package/lib/es/steps/steps.css +6 -0
- package/lib/es/upload/foundation.d.ts +8 -1
- package/lib/es/upload/foundation.js +70 -22
- package/lib/es/utils/escapeHtml.d.ts +9 -0
- package/lib/es/utils/escapeHtml.js +84 -0
- package/lib/es/utils/object.js +3 -1
- package/modal/modalFoundation.ts +33 -32
- package/package.json +35 -5
- package/pagination/foundation.ts +25 -7
- package/pincode/foundation.ts +1 -1
- package/resizable/variables.scss +2 -2
- package/select/foundation.ts +19 -8
- package/steps/bacisSteps.scss +8 -2
- package/upload/foundation.ts +81 -24
- package/utils/escapeHtml.ts +94 -0
- package/utils/object.ts +3 -1
package/upload/foundation.ts
CHANGED
|
@@ -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?:
|
|
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
|
-
|
|
1030
|
-
if (
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
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 `<` 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 `<` 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, '<'));
|
|
70
|
+
}
|
|
71
|
+
} else if (line[i] === '<') {
|
|
72
|
+
parts.push('<');
|
|
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
|
|
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);
|