@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
|
@@ -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
|
|
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
|
}
|
|
@@ -277,5 +277,44 @@ class TextAreaFoundation extends _foundation.default {
|
|
|
277
277
|
this._adapter.notifyClear(e);
|
|
278
278
|
this.stopPropagation(e);
|
|
279
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* trigger when click textarea wrapper
|
|
282
|
+
* @param {Event} e
|
|
283
|
+
*/
|
|
284
|
+
handleClick(e) {
|
|
285
|
+
const {
|
|
286
|
+
disabled,
|
|
287
|
+
readonly
|
|
288
|
+
} = this._adapter.getProps();
|
|
289
|
+
const {
|
|
290
|
+
isFocus
|
|
291
|
+
} = this._adapter.getStates();
|
|
292
|
+
if (disabled || readonly || isFocus) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
// do not handle bubbling up events
|
|
296
|
+
if (this._adapter.isEventTarget(e)) {
|
|
297
|
+
this._adapter.focusInput();
|
|
298
|
+
this._adapter.toggleFocusing(true);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* trigger when click textarea counter
|
|
303
|
+
* @param {Event} e
|
|
304
|
+
*/
|
|
305
|
+
handleCounterClick(e) {
|
|
306
|
+
const {
|
|
307
|
+
disabled,
|
|
308
|
+
readonly
|
|
309
|
+
} = this._adapter.getProps();
|
|
310
|
+
const {
|
|
311
|
+
isFocus
|
|
312
|
+
} = this._adapter.getStates();
|
|
313
|
+
if (disabled || readonly || isFocus) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
this._adapter.focusInput();
|
|
317
|
+
this._adapter.toggleFocusing(true);
|
|
318
|
+
}
|
|
280
319
|
}
|
|
281
320
|
exports.default = TextAreaFoundation;
|
|
@@ -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;
|
|
@@ -4,23 +4,55 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
var _debounce2 = _interopRequireDefault(require("lodash/debounce"));
|
|
7
8
|
var _foundation = _interopRequireDefault(require("../base/foundation"));
|
|
8
9
|
var _isPromise = _interopRequireDefault(require("../utils/isPromise"));
|
|
9
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
class ModalFoundation extends _foundation.default {
|
|
11
12
|
constructor(adapter) {
|
|
12
13
|
super(Object.assign({}, adapter));
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
this._debouncedOk = (0, _debounce2.default)(e => {
|
|
15
|
+
this._invokeOk(e);
|
|
16
|
+
}, 100, {
|
|
17
|
+
leading: true,
|
|
18
|
+
trailing: false
|
|
19
|
+
});
|
|
20
|
+
this._debouncedCancel = (0, _debounce2.default)(e => {
|
|
21
|
+
this._invokeCancel(e);
|
|
22
|
+
}, 100, {
|
|
23
|
+
leading: true,
|
|
24
|
+
trailing: false
|
|
25
|
+
});
|
|
26
|
+
this._lastCancelTarget = null;
|
|
27
|
+
this._lastOkTarget = null;
|
|
16
28
|
this.toggleDisplayNone = (displayNone, callback) => {
|
|
17
29
|
this._adapter.toggleDisplayNone(displayNone, callback);
|
|
18
30
|
};
|
|
19
31
|
}
|
|
20
32
|
destroy() {
|
|
33
|
+
this._debouncedOk.cancel();
|
|
34
|
+
this._debouncedCancel.cancel();
|
|
21
35
|
this.afterHide();
|
|
22
36
|
}
|
|
23
37
|
handleCancel(e) {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
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;
|
|
40
|
+
if (target !== this._lastCancelTarget) {
|
|
41
|
+
this._debouncedCancel.cancel();
|
|
42
|
+
}
|
|
43
|
+
this._lastCancelTarget = target;
|
|
44
|
+
this._debouncedCancel(e);
|
|
45
|
+
}
|
|
46
|
+
handleOk(e) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
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;
|
|
49
|
+
if (target !== this._lastOkTarget) {
|
|
50
|
+
this._debouncedOk.cancel();
|
|
51
|
+
}
|
|
52
|
+
this._lastOkTarget = target;
|
|
53
|
+
this._debouncedOk(e);
|
|
54
|
+
}
|
|
55
|
+
_invokeCancel(e) {
|
|
24
56
|
var _a;
|
|
25
57
|
const result = this._adapter.notifyCancel(e);
|
|
26
58
|
if ((0, _isPromise.default)(result)) {
|
|
@@ -39,7 +71,7 @@ class ModalFoundation extends _foundation.default {
|
|
|
39
71
|
});
|
|
40
72
|
}
|
|
41
73
|
}
|
|
42
|
-
|
|
74
|
+
_invokeOk(e) {
|
|
43
75
|
var _a;
|
|
44
76
|
const result = this._adapter.notifyOk(e);
|
|
45
77
|
if ((0, _isPromise.default)(result)) {
|
|
@@ -55,7 +55,13 @@ class PaginationFoundation extends _foundation.default {
|
|
|
55
55
|
prevIsDisabled = false;
|
|
56
56
|
nextIsDisabled = true;
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
const {
|
|
59
|
+
prevDisabled: currentPrevDisabled,
|
|
60
|
+
nextDisabled: currentNextDisabled
|
|
61
|
+
} = this.getStates();
|
|
62
|
+
if (prevIsDisabled !== currentPrevDisabled || nextIsDisabled !== currentNextDisabled) {
|
|
63
|
+
this._adapter.setDisabled(prevIsDisabled, nextIsDisabled);
|
|
64
|
+
}
|
|
59
65
|
}
|
|
60
66
|
goPage(targetPageIndex) {
|
|
61
67
|
if (targetPageIndex === '...') {
|
|
@@ -99,9 +105,17 @@ class PaginationFoundation extends _foundation.default {
|
|
|
99
105
|
total,
|
|
100
106
|
pageSize
|
|
101
107
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.
|
|
108
|
+
// Only call setState when value actually changed to avoid unnecessary re-renders
|
|
109
|
+
// that can cause infinite loops in React 18's concurrent batching
|
|
110
|
+
if (total !== this.getState('total')) {
|
|
111
|
+
this._adapter.updateTotal(total);
|
|
112
|
+
}
|
|
113
|
+
if (targetPageIndex !== this.getState('currentPage')) {
|
|
114
|
+
this._adapter.setCurrentPage(targetPageIndex);
|
|
115
|
+
}
|
|
116
|
+
if (pageSize !== this.getState('pageSize')) {
|
|
117
|
+
this._adapter.updatePageSize(pageSize);
|
|
118
|
+
}
|
|
105
119
|
}
|
|
106
120
|
updateAllPageNumbers(total, pageSize) {
|
|
107
121
|
// only need to update in small size
|
|
@@ -237,9 +251,16 @@ class PaginationFoundation extends _foundation.default {
|
|
|
237
251
|
total,
|
|
238
252
|
currentPage
|
|
239
253
|
} = this.getStates();
|
|
240
|
-
//
|
|
241
|
-
const
|
|
242
|
-
|
|
254
|
+
// Check if we should prevent page change when pageSize changes
|
|
255
|
+
const {
|
|
256
|
+
preventPageChangeOnPageSizeChange
|
|
257
|
+
} = this.getProps();
|
|
258
|
+
let newCurrentPage = currentPage;
|
|
259
|
+
if (!preventPageChangeOnPageSizeChange) {
|
|
260
|
+
// After converting the switching page capacity, which page is the current page
|
|
261
|
+
const currentPageFirstItemIndex = (currentPage - 1) * pageSize + 1;
|
|
262
|
+
newCurrentPage = Math.ceil(currentPageFirstItemIndex / newPageSize);
|
|
263
|
+
}
|
|
243
264
|
this.updatePage(newCurrentPage, total, newPageSize);
|
|
244
265
|
if (currentPage !== newCurrentPage) {
|
|
245
266
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
117
|
+
z-index: 20;
|
|
118
118
|
opacity: 0;
|
|
119
119
|
position: fixed;
|
|
120
120
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
$z-resizable_handler:
|
|
2
|
-
$z-resizable_background:
|
|
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;
|
|
@@ -43,20 +43,31 @@ class SelectFoundation extends _foundation.default {
|
|
|
43
43
|
}
|
|
44
44
|
const autoFocus = this.getProp('autoFocus');
|
|
45
45
|
if (autoFocus) {
|
|
46
|
-
this.focus();
|
|
46
|
+
this.focus(originalOptions);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
focus() {
|
|
49
|
+
focus(optionsForOpen) {
|
|
50
50
|
const isFilterable = this._isFilterable();
|
|
51
51
|
const isMultiple = this._isMultiple();
|
|
52
|
+
const {
|
|
53
|
+
isOpen
|
|
54
|
+
} = this.getStates();
|
|
52
55
|
this._adapter.updateFocusState(true);
|
|
53
56
|
this._adapter.setIsFocusInContainer(false);
|
|
54
|
-
if (isFilterable
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
if (isFilterable) {
|
|
58
|
+
if (isMultiple) {
|
|
59
|
+
// when filter and multiple, focus input and open dropdown
|
|
60
|
+
this.focusInput();
|
|
61
|
+
if (!isOpen) {
|
|
62
|
+
this.open(undefined, optionsForOpen);
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
// when filter and not multiple, show input, focus it and open dropdown
|
|
66
|
+
this.toggle2SearchInput(true);
|
|
67
|
+
if (!isOpen) {
|
|
68
|
+
this.open(undefined, optionsForOpen);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
60
71
|
} else {
|
|
61
72
|
this._focusTrigger();
|
|
62
73
|
}
|
|
@@ -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
|
|
package/lib/cjs/steps/steps.css
CHANGED
|
@@ -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?:
|
|
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
|
/**
|
|
@@ -57,6 +57,11 @@ class UploadFoundation extends _foundation.default {
|
|
|
57
57
|
* when _createURL is called multiple times in a sync loop.
|
|
58
58
|
*/
|
|
59
59
|
this._localUrls = {};
|
|
60
|
+
/**
|
|
61
|
+
* Flag to prevent duplicate handling of paste events.
|
|
62
|
+
* When paste event is successfully handled, we ignore the subsequent keydown event.
|
|
63
|
+
*/
|
|
64
|
+
this._pasteHandled = false;
|
|
60
65
|
}
|
|
61
66
|
init() {
|
|
62
67
|
// make sure state reset, otherwise may cause upload abort in React StrictMode, like https://github.com/DouyinFE/semi-design/pull/843
|
|
@@ -1081,40 +1086,83 @@ class UploadFoundation extends _foundation.default {
|
|
|
1081
1086
|
}
|
|
1082
1087
|
}
|
|
1083
1088
|
handlePasting(e) {
|
|
1084
|
-
const isMac = this._adapter.isMac();
|
|
1085
|
-
const isCombineKeydown = isMac ? e.metaKey : e.ctrlKey;
|
|
1086
1089
|
const {
|
|
1087
1090
|
addOnPasting
|
|
1088
1091
|
} = this.getProps();
|
|
1089
|
-
if (addOnPasting) {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
});
|
|
1104
|
-
} else {
|
|
1105
|
-
this._adapter.notifyPastingError(result);
|
|
1092
|
+
if (!addOnPasting) {
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
// Try to read from native paste event (clipboardData) first as fallback
|
|
1096
|
+
if (e.type === 'paste' && e.clipboardData && e.clipboardData.items) {
|
|
1097
|
+
const items = e.clipboardData.items;
|
|
1098
|
+
const files = [];
|
|
1099
|
+
for (let i = 0; i < items.length; i++) {
|
|
1100
|
+
const item = items[i];
|
|
1101
|
+
// Check if the item is a file (image, etc.)
|
|
1102
|
+
if (item.kind === 'file') {
|
|
1103
|
+
const file = item.getAsFile();
|
|
1104
|
+
if (file) {
|
|
1105
|
+
files.push(file);
|
|
1106
1106
|
}
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
if (files.length > 0) {
|
|
1110
|
+
e.preventDefault();
|
|
1111
|
+
this.handleChange(files);
|
|
1112
|
+
// Mark that paste event has been handled to prevent duplicate handling by keydown event
|
|
1113
|
+
this._pasteHandled = true;
|
|
1114
|
+
// Reset the flag after a short delay to allow future paste operations
|
|
1115
|
+
setTimeout(() => {
|
|
1116
|
+
this._pasteHandled = false;
|
|
1117
|
+
}, 100);
|
|
1118
|
+
return;
|
|
1110
1119
|
}
|
|
1111
1120
|
}
|
|
1121
|
+
// Fallback to navigator.clipboard for keyboard events (keydown with Ctrl/Cmd+V)
|
|
1122
|
+
// Skip if paste event has already been handled
|
|
1123
|
+
if (this._pasteHandled) {
|
|
1124
|
+
this._pasteHandled = false;
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
const isMac = this._adapter.isMac();
|
|
1128
|
+
const isCombineKeydown = isMac ? e.metaKey : e.ctrlKey;
|
|
1129
|
+
if (isCombineKeydown && e.code === 'KeyV') {
|
|
1130
|
+
// Check if navigator.clipboard is available
|
|
1131
|
+
if (!navigator.clipboard || typeof navigator.clipboard.read !== 'function') {
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
// https://github.com/microsoft/TypeScript/issues/33923
|
|
1135
|
+
const permissionName = 'clipboard-read';
|
|
1136
|
+
// The main thread should not be blocked by clipboard, so callback writing is required here. No await here
|
|
1137
|
+
navigator.permissions.query({
|
|
1138
|
+
name: permissionName
|
|
1139
|
+
}).then(result => {
|
|
1140
|
+
if (result.state === 'granted' || result.state === 'prompt') {
|
|
1141
|
+
// user has authorized or will authorize
|
|
1142
|
+
navigator.clipboard.read().then(clipboardItems => {
|
|
1143
|
+
// Process the data read from the pasteboard
|
|
1144
|
+
// Check the returned data type to determine if it is image data, and process accordingly
|
|
1145
|
+
this.readFileFromClipboard(clipboardItems);
|
|
1146
|
+
}).catch(error => {
|
|
1147
|
+
this._adapter.notifyPastingError(error);
|
|
1148
|
+
});
|
|
1149
|
+
} else {
|
|
1150
|
+
this._adapter.notifyPastingError(result);
|
|
1151
|
+
}
|
|
1152
|
+
}).catch(error => {
|
|
1153
|
+
this._adapter.notifyPastingError(error);
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1112
1156
|
}
|
|
1113
1157
|
bindPastingHandler() {
|
|
1158
|
+
// Register keyboard event handler (keydown with Ctrl/Cmd+V)
|
|
1114
1159
|
this._adapter.registerPastingHandler(event => this.handlePasting(event));
|
|
1160
|
+
// Register native paste event handler as fallback
|
|
1161
|
+
this._adapter.registerPasteEventHandler(event => this.handlePasting(event));
|
|
1115
1162
|
}
|
|
1116
1163
|
unbindPastingHandler() {
|
|
1117
1164
|
this._adapter.unRegisterPastingHandler();
|
|
1165
|
+
this._adapter.unRegisterPasteEventHandler();
|
|
1118
1166
|
}
|
|
1119
1167
|
}
|
|
1120
1168
|
var _default = exports.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 `<` 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,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.escapeHtmlInMarkdown = escapeHtmlInMarkdown;
|
|
7
|
+
/**
|
|
8
|
+
* Escape HTML angle brackets in markdown text, preserving code blocks and inline code.
|
|
9
|
+
*
|
|
10
|
+
* In `format='md'` mode, @mdx-js/mdx uses `rehypeRemoveRaw` which strips all raw HTML nodes.
|
|
11
|
+
* This causes user-typed HTML-like content (e.g. `<AgentChat />`) to silently disappear.
|
|
12
|
+
* By escaping `<` to `<` outside of code spans/blocks, the markdown parser treats them
|
|
13
|
+
* as literal text instead of HTML tags.
|
|
14
|
+
*/
|
|
15
|
+
function escapeHtmlInMarkdown(text) {
|
|
16
|
+
const lines = text.split('\n');
|
|
17
|
+
const result = [];
|
|
18
|
+
let fenceChar = null;
|
|
19
|
+
let fenceLen = 0;
|
|
20
|
+
for (let i = 0; i < lines.length; i++) {
|
|
21
|
+
const line = lines[i];
|
|
22
|
+
if (fenceChar !== null) {
|
|
23
|
+
// Inside a fenced code block — check for closing fence
|
|
24
|
+
result.push(line);
|
|
25
|
+
const trimmed = line.trimEnd();
|
|
26
|
+
if (trimmed.length >= fenceLen && trimmed[0] === fenceChar && trimmed === fenceChar.repeat(trimmed.length)) {
|
|
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
|
+
return result.join('\n');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Escape `<` to `<` in a single line, but preserve content inside inline code spans.
|
|
45
|
+
*/
|
|
46
|
+
function escapeAngleBracketsOutsideInlineCode(line) {
|
|
47
|
+
const parts = [];
|
|
48
|
+
let i = 0;
|
|
49
|
+
while (i < line.length) {
|
|
50
|
+
if (line[i] === '`') {
|
|
51
|
+
// Count opening backticks
|
|
52
|
+
let count = 0;
|
|
53
|
+
const start = i;
|
|
54
|
+
while (i < line.length && line[i] === '`') {
|
|
55
|
+
count++;
|
|
56
|
+
i++;
|
|
57
|
+
}
|
|
58
|
+
// Find matching closing backticks (exact same count)
|
|
59
|
+
const closer = '`'.repeat(count);
|
|
60
|
+
const closeIdx = line.indexOf(closer, i);
|
|
61
|
+
if (closeIdx !== -1) {
|
|
62
|
+
parts.push(line.slice(start, closeIdx + count));
|
|
63
|
+
i = closeIdx + count;
|
|
64
|
+
} else {
|
|
65
|
+
// No matching close — treat backticks as regular text, escape any `<`
|
|
66
|
+
parts.push(line.slice(start, i).replace(/</g, '<'));
|
|
67
|
+
}
|
|
68
|
+
} else if (line[i] === '<') {
|
|
69
|
+
parts.push('<');
|
|
70
|
+
i++;
|
|
71
|
+
} else {
|
|
72
|
+
// Collect a run of non-special characters at once
|
|
73
|
+
const next = line.indexOf('<', i);
|
|
74
|
+
const nextBt = line.indexOf('`', i);
|
|
75
|
+
let end;
|
|
76
|
+
if (next === -1 && nextBt === -1) {
|
|
77
|
+
end = line.length;
|
|
78
|
+
} else if (next === -1) {
|
|
79
|
+
end = nextBt;
|
|
80
|
+
} else if (nextBt === -1) {
|
|
81
|
+
end = next;
|
|
82
|
+
} else {
|
|
83
|
+
end = Math.min(next, nextBt);
|
|
84
|
+
}
|
|
85
|
+
parts.push(line.slice(i, end));
|
|
86
|
+
i = end;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return parts.join('');
|
|
90
|
+
}
|
package/lib/cjs/utils/object.js
CHANGED
|
@@ -64,7 +64,9 @@ function cleanup(obj, path) {
|
|
|
64
64
|
// lodashRemove(target, (value, index, array) => index > lastIndex);
|
|
65
65
|
// }
|
|
66
66
|
// Delete object if its empty
|
|
67
|
-
if
|
|
67
|
+
// Only delete array if it's not empty AND all elements are null/undefined
|
|
68
|
+
// This prevents empty arrays from being deleted (issue #2834)
|
|
69
|
+
if (Array.isArray(target) && target.length > 0 && target.every(e => e == null)) {
|
|
68
70
|
(0, _unset2.default)(obj, path);
|
|
69
71
|
} else if (isEmptyObject(target)) {
|
|
70
72
|
(0, _unset2.default)(obj, path);
|
|
@@ -353,7 +353,9 @@ export default class AIChatInputFoundation extends BaseFoundation {
|
|
|
353
353
|
};
|
|
354
354
|
this.handRichTextArealKeyDown = (view, event) => {
|
|
355
355
|
var _a;
|
|
356
|
-
|
|
356
|
+
if (view.composing) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
357
359
|
const {
|
|
358
360
|
sendHotKey
|
|
359
361
|
} = this.getProps();
|
|
@@ -13,6 +13,7 @@ export interface DataItem {
|
|
|
13
13
|
export interface StateOptionItem extends DataItem {
|
|
14
14
|
show?: boolean;
|
|
15
15
|
key?: string | number;
|
|
16
|
+
_renderedLabel?: any;
|
|
16
17
|
}
|
|
17
18
|
export type AutoCompleteData = Array<DataItem | string>;
|
|
18
19
|
export interface AutoCompleteAdapter<P = Record<string, any>, S = Record<string, any>> extends KeyboardAdapter<P, S> {
|
|
@@ -112,7 +112,7 @@ class AutoCompleteFoundation extends BaseFoundation {
|
|
|
112
112
|
}, item);
|
|
113
113
|
}
|
|
114
114
|
if (renderItem && typeof renderItem === 'function') {
|
|
115
|
-
option.
|
|
115
|
+
option._renderedLabel = renderItem(item);
|
|
116
116
|
}
|
|
117
117
|
options.push(option);
|
|
118
118
|
});
|