@douyinfe/semi-foundation 2.101.1 → 2.103.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.
- package/button/button.scss +1 -0
- package/dragMove/foundation.ts +36 -3
- package/lib/cjs/button/button.css +1 -0
- package/lib/cjs/button/button.scss +1 -0
- package/lib/cjs/dragMove/foundation.d.ts +5 -0
- package/lib/cjs/dragMove/foundation.js +27 -3
- package/lib/cjs/progress/progress.css +48 -0
- package/lib/cjs/progress/progress.scss +60 -1
- package/lib/cjs/tree/foundation.js +4 -1
- package/lib/cjs/upload/foundation.d.ts +27 -0
- package/lib/cjs/upload/foundation.js +75 -33
- package/lib/es/button/button.css +1 -0
- package/lib/es/button/button.scss +1 -0
- package/lib/es/dragMove/foundation.d.ts +5 -0
- package/lib/es/dragMove/foundation.js +27 -3
- package/lib/es/progress/progress.css +48 -0
- package/lib/es/progress/progress.scss +60 -1
- package/lib/es/tree/foundation.js +4 -1
- package/lib/es/upload/foundation.d.ts +27 -0
- package/lib/es/upload/foundation.js +75 -33
- package/package.json +4 -4
- package/progress/progress.scss +60 -1
- package/tree/foundation.ts +4 -1
- package/upload/foundation.ts +81 -27
package/button/button.scss
CHANGED
|
@@ -19,6 +19,7 @@ $module: #{$prefix}-button;
|
|
|
19
19
|
padding-right: $spacing-button_default-paddingRight;
|
|
20
20
|
padding-top: $spacing-button_default-paddingTop;
|
|
21
21
|
padding-bottom: $spacing-button_default-paddingTop;
|
|
22
|
+
font-family: inherit;
|
|
22
23
|
font-size: $font-button-fontSize;
|
|
23
24
|
line-height: $font-button-lineHeight;
|
|
24
25
|
font-weight: $font-button-fontWeight;
|
package/dragMove/foundation.ts
CHANGED
|
@@ -25,6 +25,10 @@ export default class DragMoveFoundation<P = Record<string, any>, S = Record<stri
|
|
|
25
25
|
yMin: number;
|
|
26
26
|
startOffsetX: number;
|
|
27
27
|
startOffsetY: number;
|
|
28
|
+
startClientX: number;
|
|
29
|
+
startClientY: number;
|
|
30
|
+
startLeft: number;
|
|
31
|
+
startTop: number;
|
|
28
32
|
|
|
29
33
|
get constrainer() {
|
|
30
34
|
return this._adapter.getConstrainer();
|
|
@@ -44,11 +48,15 @@ export default class DragMoveFoundation<P = Record<string, any>, S = Record<stri
|
|
|
44
48
|
throw new Error('drag element must be a valid element');
|
|
45
49
|
}
|
|
46
50
|
this.element = element;
|
|
47
|
-
this.
|
|
51
|
+
this.updatePositionStrategy();
|
|
48
52
|
this.handler.style.cursor = 'move';
|
|
49
53
|
this._registerStartEvent();
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
updatePositionStrategy = () => {
|
|
57
|
+
this.element.style.position = this.getProp('positionStrategy') === 'relative' ? 'relative' : 'absolute';
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
_registerStartEvent = () => {
|
|
53
61
|
this.handler.addEventListener('mousedown', this.onMouseDown);
|
|
54
62
|
this.handler.addEventListener('touchstart', this.onTouchStart);
|
|
@@ -95,6 +103,18 @@ export default class DragMoveFoundation<P = Record<string, any>, S = Record<stri
|
|
|
95
103
|
_calcMoveRange() {
|
|
96
104
|
// Calculate the range within which an element can move
|
|
97
105
|
if (this.constrainer) {
|
|
106
|
+
if (this.getProp('positionStrategy') === 'relative') {
|
|
107
|
+
const elementRect = this.element.getBoundingClientRect();
|
|
108
|
+
const constrainerRect = this.constrainer.getBoundingClientRect();
|
|
109
|
+
const style = window.getComputedStyle(this.element);
|
|
110
|
+
const currentLeft = parseFloat(style.left) || 0;
|
|
111
|
+
const currentTop = parseFloat(style.top) || 0;
|
|
112
|
+
this.xMin = currentLeft + constrainerRect.left - elementRect.left;
|
|
113
|
+
this.xMax = currentLeft + constrainerRect.right - elementRect.right;
|
|
114
|
+
this.yMin = currentTop + constrainerRect.top - elementRect.top;
|
|
115
|
+
this.yMax = currentTop + constrainerRect.bottom - elementRect.bottom;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
98
118
|
let node = this.element.offsetParent as HTMLElement;
|
|
99
119
|
let startX = 0;
|
|
100
120
|
let startY = 0;
|
|
@@ -126,6 +146,14 @@ export default class DragMoveFoundation<P = Record<string, any>, S = Record<stri
|
|
|
126
146
|
}
|
|
127
147
|
|
|
128
148
|
_calcOffset = (e: Touch | MouseEvent) => {
|
|
149
|
+
if (this.getProp('positionStrategy') === 'relative') {
|
|
150
|
+
const style = window.getComputedStyle(this.element);
|
|
151
|
+
this.startClientX = e.clientX;
|
|
152
|
+
this.startClientY = e.clientY;
|
|
153
|
+
this.startLeft = parseFloat(style.left) || 0;
|
|
154
|
+
this.startTop = parseFloat(style.top) || 0;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
129
157
|
this.startOffsetX = e.clientX - this.element.offsetLeft;
|
|
130
158
|
this.startOffsetY = e.clientY - this.element.offsetTop;
|
|
131
159
|
}
|
|
@@ -161,8 +189,13 @@ export default class DragMoveFoundation<P = Record<string, any>, S = Record<stri
|
|
|
161
189
|
|
|
162
190
|
_changePos = (e: Touch | MouseEvent) => {
|
|
163
191
|
const { customMove } = this.getProps();
|
|
164
|
-
|
|
165
|
-
let
|
|
192
|
+
const useRelativePosition = this.getProp('positionStrategy') === 'relative';
|
|
193
|
+
let newLeft = useRelativePosition ?
|
|
194
|
+
this.startLeft + e.clientX - this.startClientX :
|
|
195
|
+
e.clientX - this.startOffsetX;
|
|
196
|
+
let newTop = useRelativePosition ?
|
|
197
|
+
this.startTop + e.clientY - this.startClientY :
|
|
198
|
+
e.clientY - this.startOffsetY;
|
|
166
199
|
if (this.constrainer) {
|
|
167
200
|
newLeft = clampValueInRange(newLeft, this.xMin, this.xMax);
|
|
168
201
|
newTop = clampValueInRange(newTop, this.yMin, this.yMax);
|
|
@@ -19,6 +19,7 @@ $module: #{$prefix}-button;
|
|
|
19
19
|
padding-right: $spacing-button_default-paddingRight;
|
|
20
20
|
padding-top: $spacing-button_default-paddingTop;
|
|
21
21
|
padding-bottom: $spacing-button_default-paddingTop;
|
|
22
|
+
font-family: inherit;
|
|
22
23
|
font-size: $font-button-fontSize;
|
|
23
24
|
line-height: $font-button-lineHeight;
|
|
24
25
|
font-weight: $font-button-fontWeight;
|
|
@@ -20,10 +20,15 @@ export default class DragMoveFoundation<P = Record<string, any>, S = Record<stri
|
|
|
20
20
|
yMin: number;
|
|
21
21
|
startOffsetX: number;
|
|
22
22
|
startOffsetY: number;
|
|
23
|
+
startClientX: number;
|
|
24
|
+
startClientY: number;
|
|
25
|
+
startLeft: number;
|
|
26
|
+
startTop: number;
|
|
23
27
|
get constrainer(): HTMLElement;
|
|
24
28
|
get handler(): HTMLElement;
|
|
25
29
|
constructor(adapter: DragMoveAdapter<P, S>);
|
|
26
30
|
init(): void;
|
|
31
|
+
updatePositionStrategy: () => void;
|
|
27
32
|
_registerStartEvent: () => void;
|
|
28
33
|
_unRegisterStartEvent: () => void;
|
|
29
34
|
destroy(): void;
|
|
@@ -19,6 +19,9 @@ class DragMoveFoundation extends _foundation.default {
|
|
|
19
19
|
}
|
|
20
20
|
constructor(adapter) {
|
|
21
21
|
super(Object.assign({}, adapter));
|
|
22
|
+
this.updatePositionStrategy = () => {
|
|
23
|
+
this.element.style.position = this.getProp('positionStrategy') === 'relative' ? 'relative' : 'absolute';
|
|
24
|
+
};
|
|
22
25
|
this._registerStartEvent = () => {
|
|
23
26
|
this.handler.addEventListener('mousedown', this.onMouseDown);
|
|
24
27
|
this.handler.addEventListener('touchstart', this.onTouchStart);
|
|
@@ -46,6 +49,14 @@ class DragMoveFoundation extends _foundation.default {
|
|
|
46
49
|
document.removeEventListener('touchcancel', this._onTouchCancel);
|
|
47
50
|
};
|
|
48
51
|
this._calcOffset = e => {
|
|
52
|
+
if (this.getProp('positionStrategy') === 'relative') {
|
|
53
|
+
const style = window.getComputedStyle(this.element);
|
|
54
|
+
this.startClientX = e.clientX;
|
|
55
|
+
this.startClientY = e.clientY;
|
|
56
|
+
this.startLeft = parseFloat(style.left) || 0;
|
|
57
|
+
this.startTop = parseFloat(style.top) || 0;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
49
60
|
this.startOffsetX = e.clientX - this.element.offsetLeft;
|
|
50
61
|
this.startOffsetY = e.clientY - this.element.offsetTop;
|
|
51
62
|
};
|
|
@@ -79,8 +90,9 @@ class DragMoveFoundation extends _foundation.default {
|
|
|
79
90
|
const {
|
|
80
91
|
customMove
|
|
81
92
|
} = this.getProps();
|
|
82
|
-
|
|
83
|
-
let
|
|
93
|
+
const useRelativePosition = this.getProp('positionStrategy') === 'relative';
|
|
94
|
+
let newLeft = useRelativePosition ? this.startLeft + e.clientX - this.startClientX : e.clientX - this.startOffsetX;
|
|
95
|
+
let newTop = useRelativePosition ? this.startTop + e.clientY - this.startClientY : e.clientY - this.startOffsetY;
|
|
84
96
|
if (this.constrainer) {
|
|
85
97
|
newLeft = clampValueInRange(newLeft, this.xMin, this.xMax);
|
|
86
98
|
newTop = clampValueInRange(newTop, this.yMin, this.yMax);
|
|
@@ -122,7 +134,7 @@ class DragMoveFoundation extends _foundation.default {
|
|
|
122
134
|
throw new Error('drag element must be a valid element');
|
|
123
135
|
}
|
|
124
136
|
this.element = element;
|
|
125
|
-
this.
|
|
137
|
+
this.updatePositionStrategy();
|
|
126
138
|
this.handler.style.cursor = 'move';
|
|
127
139
|
this._registerStartEvent();
|
|
128
140
|
}
|
|
@@ -137,6 +149,18 @@ class DragMoveFoundation extends _foundation.default {
|
|
|
137
149
|
_calcMoveRange() {
|
|
138
150
|
// Calculate the range within which an element can move
|
|
139
151
|
if (this.constrainer) {
|
|
152
|
+
if (this.getProp('positionStrategy') === 'relative') {
|
|
153
|
+
const elementRect = this.element.getBoundingClientRect();
|
|
154
|
+
const constrainerRect = this.constrainer.getBoundingClientRect();
|
|
155
|
+
const style = window.getComputedStyle(this.element);
|
|
156
|
+
const currentLeft = parseFloat(style.left) || 0;
|
|
157
|
+
const currentTop = parseFloat(style.top) || 0;
|
|
158
|
+
this.xMin = currentLeft + constrainerRect.left - elementRect.left;
|
|
159
|
+
this.xMax = currentLeft + constrainerRect.right - elementRect.right;
|
|
160
|
+
this.yMin = currentTop + constrainerRect.top - elementRect.top;
|
|
161
|
+
this.yMax = currentTop + constrainerRect.bottom - elementRect.bottom;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
140
164
|
let node = this.element.offsetParent;
|
|
141
165
|
let startX = 0;
|
|
142
166
|
let startY = 0;
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
.semi-progress-horizontal .semi-progress-track {
|
|
21
21
|
height: 100%;
|
|
22
22
|
width: 100%;
|
|
23
|
+
overflow: hidden;
|
|
23
24
|
}
|
|
24
25
|
.semi-progress-horizontal .semi-progress-track-inner {
|
|
25
26
|
height: 100%;
|
|
@@ -28,6 +29,11 @@
|
|
|
28
29
|
transition: width 0.3s;
|
|
29
30
|
transition-timing-function: cubic-bezier(0.62, 0.05, 0.36, 0.95);
|
|
30
31
|
}
|
|
32
|
+
.semi-progress-horizontal .semi-progress-track-inner-indeterminate {
|
|
33
|
+
width: 35%;
|
|
34
|
+
transition: none;
|
|
35
|
+
animation: semi-progress-indeterminate-slide 1.6s ease-in-out infinite;
|
|
36
|
+
}
|
|
31
37
|
.semi-progress-horizontal .semi-progress-line-text {
|
|
32
38
|
min-width: 45px;
|
|
33
39
|
font-weight: 600;
|
|
@@ -48,6 +54,7 @@
|
|
|
48
54
|
.semi-progress-vertical .semi-progress-track {
|
|
49
55
|
height: 100%;
|
|
50
56
|
width: 100%;
|
|
57
|
+
overflow: hidden;
|
|
51
58
|
}
|
|
52
59
|
.semi-progress-vertical .semi-progress-track-inner {
|
|
53
60
|
background-color: var(--semi-color-success);
|
|
@@ -56,6 +63,12 @@
|
|
|
56
63
|
transition: height 0.3s;
|
|
57
64
|
transition-timing-function: cubic-bezier(0.62, 0.05, 0.36, 0.95);
|
|
58
65
|
}
|
|
66
|
+
.semi-progress-vertical .semi-progress-track-inner-indeterminate {
|
|
67
|
+
height: 35%;
|
|
68
|
+
width: 100%;
|
|
69
|
+
transition: none;
|
|
70
|
+
animation: semi-progress-indeterminate-slide-vertical 1.6s ease-in-out infinite;
|
|
71
|
+
}
|
|
59
72
|
.semi-progress-vertical .semi-progress-line-text {
|
|
60
73
|
font-weight: 600;
|
|
61
74
|
margin-top: 8px;
|
|
@@ -77,6 +90,11 @@
|
|
|
77
90
|
transform-origin: 50% 50%;
|
|
78
91
|
stroke: var(--semi-color-success);
|
|
79
92
|
}
|
|
93
|
+
.semi-progress-circle-ring-inner-indeterminate {
|
|
94
|
+
transform: rotate(0deg);
|
|
95
|
+
transform-origin: 50% 50%;
|
|
96
|
+
animation: semi-progress-indeterminate-rotate 1.2s linear infinite;
|
|
97
|
+
}
|
|
80
98
|
.semi-progress-circle-text {
|
|
81
99
|
position: absolute;
|
|
82
100
|
top: 50%;
|
|
@@ -88,6 +106,36 @@
|
|
|
88
106
|
color: var(--semi-color-mode-minor-text);
|
|
89
107
|
}
|
|
90
108
|
|
|
109
|
+
@keyframes semi-progress-indeterminate-slide {
|
|
110
|
+
0% {
|
|
111
|
+
transform: translateX(-120%);
|
|
112
|
+
}
|
|
113
|
+
55% {
|
|
114
|
+
transform: translateX(300%);
|
|
115
|
+
}
|
|
116
|
+
100% {
|
|
117
|
+
transform: translateX(300%);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
@keyframes semi-progress-indeterminate-slide-vertical {
|
|
121
|
+
0% {
|
|
122
|
+
transform: translateY(-120%);
|
|
123
|
+
}
|
|
124
|
+
55% {
|
|
125
|
+
transform: translateY(300%);
|
|
126
|
+
}
|
|
127
|
+
100% {
|
|
128
|
+
transform: translateY(300%);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
@keyframes semi-progress-indeterminate-rotate {
|
|
132
|
+
from {
|
|
133
|
+
transform: rotate(0deg);
|
|
134
|
+
}
|
|
135
|
+
to {
|
|
136
|
+
transform: rotate(360deg);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
91
139
|
.semi-rtl .semi-progress,
|
|
92
140
|
.semi-portal-rtl .semi-progress {
|
|
93
141
|
direction: rtl;
|
|
@@ -23,6 +23,7 @@ $module: #{$prefix}-progress;
|
|
|
23
23
|
.#{$module}-track {
|
|
24
24
|
height: 100%;
|
|
25
25
|
width: 100%;
|
|
26
|
+
overflow: hidden;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
.#{$module}-track-inner {
|
|
@@ -33,6 +34,12 @@ $module: #{$prefix}-progress;
|
|
|
33
34
|
transition-timing-function: $motion-progress-transition_timing_function;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
.#{$module}-track-inner-indeterminate {
|
|
38
|
+
width: 35%;
|
|
39
|
+
transition: none;
|
|
40
|
+
animation: semi-progress-indeterminate-slide 1.6s ease-in-out infinite;
|
|
41
|
+
}
|
|
42
|
+
|
|
36
43
|
.#{$module}-line-text {
|
|
37
44
|
min-width: $width-progress_line_text;
|
|
38
45
|
font-weight: $font-progress_line_text-fontWeight;
|
|
@@ -57,6 +64,7 @@ $module: #{$prefix}-progress;
|
|
|
57
64
|
.#{$module}-track {
|
|
58
65
|
height: 100%;
|
|
59
66
|
width: 100%;
|
|
67
|
+
overflow: hidden;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
.#{$module}-track-inner {
|
|
@@ -67,6 +75,13 @@ $module: #{$prefix}-progress;
|
|
|
67
75
|
transition-timing-function: $motion-progress-transition_timing_function;
|
|
68
76
|
}
|
|
69
77
|
|
|
78
|
+
.#{$module}-track-inner-indeterminate {
|
|
79
|
+
height: 35%;
|
|
80
|
+
width: 100%;
|
|
81
|
+
transition: none;
|
|
82
|
+
animation: semi-progress-indeterminate-slide-vertical 1.6s ease-in-out infinite;
|
|
83
|
+
}
|
|
84
|
+
|
|
70
85
|
.#{$module}-line-text {
|
|
71
86
|
font-weight: $font-progress_line_text-fontWeight;
|
|
72
87
|
margin-top: $spacing-progress_vertical_line_text-marginTop;
|
|
@@ -95,6 +110,12 @@ $module: #{$prefix}-progress;
|
|
|
95
110
|
stroke: $color-progress_track_inner-bg;
|
|
96
111
|
}
|
|
97
112
|
|
|
113
|
+
&-ring-inner-indeterminate {
|
|
114
|
+
transform: rotate(0deg);
|
|
115
|
+
transform-origin: 50% 50%;
|
|
116
|
+
animation: semi-progress-indeterminate-rotate 1.2s linear infinite;
|
|
117
|
+
}
|
|
118
|
+
|
|
98
119
|
&-text {
|
|
99
120
|
position: absolute;
|
|
100
121
|
top: 50%;
|
|
@@ -108,4 +129,42 @@ $module: #{$prefix}-progress;
|
|
|
108
129
|
}
|
|
109
130
|
}
|
|
110
131
|
|
|
111
|
-
@
|
|
132
|
+
@keyframes semi-progress-indeterminate-slide {
|
|
133
|
+
0% {
|
|
134
|
+
transform: translateX(-120%);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
55% {
|
|
138
|
+
transform: translateX(300%);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
100% {
|
|
142
|
+
transform: translateX(300%);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@keyframes semi-progress-indeterminate-slide-vertical {
|
|
147
|
+
0% {
|
|
148
|
+
transform: translateY(-120%);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
55% {
|
|
152
|
+
transform: translateY(300%);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
100% {
|
|
156
|
+
transform: translateY(300%);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@keyframes semi-progress-indeterminate-rotate {
|
|
161
|
+
from {
|
|
162
|
+
transform: rotate(0deg);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
to {
|
|
166
|
+
transform: rotate(360deg);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@import './rtl.scss';
|
|
@@ -440,7 +440,10 @@ class TreeFoundation extends _foundation.default {
|
|
|
440
440
|
this._adapter.cacheFlattenNodes(motionType === 'hide' && this._isAnimated());
|
|
441
441
|
if (!this._isExpandControlled()) {
|
|
442
442
|
const flattenNodes = (0, _treeUtil.flattenTreeData)(treeData, expandedKeys, keyMaps, isSearching && showFilteredOnly && filteredShownKeys);
|
|
443
|
-
|
|
443
|
+
let motionKeys = this._isAnimated() ? (0, _treeUtil.getMotionKeys)(eventKey, expandedKeys, keyEntities) : [];
|
|
444
|
+
if (isSearching && showFilteredOnly) {
|
|
445
|
+
motionKeys = motionKeys.filter(key => filteredShownKeys.has(key));
|
|
446
|
+
}
|
|
444
447
|
const newState = {
|
|
445
448
|
[expandedStateKey]: expandedKeys,
|
|
446
449
|
flattenNodes,
|
|
@@ -94,6 +94,33 @@ declare class UploadFoundation<P = Record<string, any>, S = Record<string, any>>
|
|
|
94
94
|
* When paste event is successfully handled, we ignore the subsequent keydown event.
|
|
95
95
|
*/
|
|
96
96
|
_pasteHandled: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Working copy of fileList used during a synchronous startUpload batch.
|
|
99
|
+
* Do NOT rely on React state fileList here: setState is async (batched in React 18),
|
|
100
|
+
* so reading getState('fileList') between iterations of a sync loop returns a stale
|
|
101
|
+
* snapshot and earlier removals get overwritten by later ones (see #3335).
|
|
102
|
+
* Seeded at the start of startUpload and cleared when the sync loop finishes (see
|
|
103
|
+
* try/finally in startUpload); async (promise) results fall back to _latestFileList
|
|
104
|
+
* then React state.
|
|
105
|
+
*/
|
|
106
|
+
_batchFileList: Array<BaseFileItem> | null;
|
|
107
|
+
/**
|
|
108
|
+
* The most recent fileList produced by handleBeforeUploadResultInObject.
|
|
109
|
+
* Unlike React state (which is flushed asynchronously under React 18 automatic
|
|
110
|
+
* batching), this is updated synchronously, so a later async beforeUpload result
|
|
111
|
+
* composes with earlier sync removals of the same batch instead of reading a stale
|
|
112
|
+
* snapshot (mixed sync + async beforeUpload results, see #3335).
|
|
113
|
+
*/
|
|
114
|
+
_latestFileList: Array<BaseFileItem> | null;
|
|
115
|
+
/**
|
|
116
|
+
* Unify all fileList commits: keep _latestFileList in sync synchronously so async
|
|
117
|
+
* beforeUpload results compose with recent mutations even before React flushes
|
|
118
|
+
* setState (React 18 automatic batching). (#3335)
|
|
119
|
+
*/
|
|
120
|
+
updateFileListInternal(newFileList: Array<BaseFileItem>, callback?: () => void): void;
|
|
121
|
+
/** Keep the synchronous snapshot aligned with an externally controlled fileList. */
|
|
122
|
+
syncLatestFileList(fileList: Array<BaseFileItem>): void;
|
|
123
|
+
getLatestFileList(): Array<BaseFileItem>;
|
|
97
124
|
constructor(adapter: UploadAdapter<P, S>);
|
|
98
125
|
init(): void;
|
|
99
126
|
/**
|
|
@@ -48,6 +48,25 @@ const {
|
|
|
48
48
|
TRIGGER_AUTO
|
|
49
49
|
} = _constants.strings;
|
|
50
50
|
class UploadFoundation extends _foundation.default {
|
|
51
|
+
/**
|
|
52
|
+
* Unify all fileList commits: keep _latestFileList in sync synchronously so async
|
|
53
|
+
* beforeUpload results compose with recent mutations even before React flushes
|
|
54
|
+
* setState (React 18 automatic batching). (#3335)
|
|
55
|
+
*/
|
|
56
|
+
updateFileListInternal(newFileList, callback) {
|
|
57
|
+
if (this._batchFileList) {
|
|
58
|
+
this._batchFileList = newFileList;
|
|
59
|
+
}
|
|
60
|
+
this._latestFileList = newFileList;
|
|
61
|
+
this._adapter.updateFileList(newFileList, callback);
|
|
62
|
+
}
|
|
63
|
+
/** Keep the synchronous snapshot aligned with an externally controlled fileList. */
|
|
64
|
+
syncLatestFileList(fileList) {
|
|
65
|
+
this._latestFileList = fileList.slice();
|
|
66
|
+
}
|
|
67
|
+
getLatestFileList() {
|
|
68
|
+
return this._batchFileList || this._latestFileList || this.getState('fileList');
|
|
69
|
+
}
|
|
51
70
|
constructor(adapter) {
|
|
52
71
|
super(Object.assign({}, adapter));
|
|
53
72
|
this.destroyState = false;
|
|
@@ -62,10 +81,29 @@ class UploadFoundation extends _foundation.default {
|
|
|
62
81
|
* When paste event is successfully handled, we ignore the subsequent keydown event.
|
|
63
82
|
*/
|
|
64
83
|
this._pasteHandled = false;
|
|
84
|
+
/**
|
|
85
|
+
* Working copy of fileList used during a synchronous startUpload batch.
|
|
86
|
+
* Do NOT rely on React state fileList here: setState is async (batched in React 18),
|
|
87
|
+
* so reading getState('fileList') between iterations of a sync loop returns a stale
|
|
88
|
+
* snapshot and earlier removals get overwritten by later ones (see #3335).
|
|
89
|
+
* Seeded at the start of startUpload and cleared when the sync loop finishes (see
|
|
90
|
+
* try/finally in startUpload); async (promise) results fall back to _latestFileList
|
|
91
|
+
* then React state.
|
|
92
|
+
*/
|
|
93
|
+
this._batchFileList = null;
|
|
94
|
+
/**
|
|
95
|
+
* The most recent fileList produced by handleBeforeUploadResultInObject.
|
|
96
|
+
* Unlike React state (which is flushed asynchronously under React 18 automatic
|
|
97
|
+
* batching), this is updated synchronously, so a later async beforeUpload result
|
|
98
|
+
* composes with earlier sync removals of the same batch instead of reading a stale
|
|
99
|
+
* snapshot (mixed sync + async beforeUpload results, see #3335).
|
|
100
|
+
*/
|
|
101
|
+
this._latestFileList = null;
|
|
65
102
|
}
|
|
66
103
|
init() {
|
|
67
104
|
// make sure state reset, otherwise may cause upload abort in React StrictMode, like https://github.com/DouyinFE/semi-design/pull/843
|
|
68
105
|
this.destroyState = false;
|
|
106
|
+
this.syncLatestFileList(this.getState('fileList'));
|
|
69
107
|
// In controlled mode, parent may keep and pass back fileList with blob url.
|
|
70
108
|
// Sync them into internal map so later remove/clear can revoke correctly.
|
|
71
109
|
this._syncLocalUrlsFromFileList();
|
|
@@ -115,6 +153,8 @@ class UploadFoundation extends _foundation.default {
|
|
|
115
153
|
if (!disabled) {
|
|
116
154
|
this.unbindPastingHandler();
|
|
117
155
|
}
|
|
156
|
+
this._batchFileList = null;
|
|
157
|
+
this._latestFileList = null;
|
|
118
158
|
this.destroyState = true;
|
|
119
159
|
}
|
|
120
160
|
/**
|
|
@@ -331,7 +371,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
331
371
|
currentFile: newFileItem,
|
|
332
372
|
fileList: newFileList
|
|
333
373
|
});
|
|
334
|
-
this.
|
|
374
|
+
this.updateFileListInternal(newFileList, () => {
|
|
335
375
|
this._adapter.resetReplaceInput();
|
|
336
376
|
if (!newFileItem._sizeInvalid) {
|
|
337
377
|
this.upload(newFileItem);
|
|
@@ -375,7 +415,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
375
415
|
fileList: currentFiles,
|
|
376
416
|
currentFile: currentFiles[0]
|
|
377
417
|
});
|
|
378
|
-
this.
|
|
418
|
+
this.updateFileListInternal(currentFiles, () => {
|
|
379
419
|
if (uploadTrigger === TRIGGER_AUTO) {
|
|
380
420
|
this.startUpload(currentFiles);
|
|
381
421
|
}
|
|
@@ -399,7 +439,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
399
439
|
});
|
|
400
440
|
}
|
|
401
441
|
});
|
|
402
|
-
this.
|
|
442
|
+
this.updateFileListInternal(fileList, () => {
|
|
403
443
|
if (uploadTrigger === TRIGGER_AUTO) {
|
|
404
444
|
this.startUpload(currentFiles);
|
|
405
445
|
}
|
|
@@ -483,7 +523,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
483
523
|
fileList: newFileList,
|
|
484
524
|
currentFile: null
|
|
485
525
|
});
|
|
486
|
-
this.
|
|
526
|
+
this.updateFileListInternal(newFileList, () => {
|
|
487
527
|
if (uploadTrigger === TRIGGER_AUTO) {
|
|
488
528
|
this.startUpload(fileItemList);
|
|
489
529
|
}
|
|
@@ -492,15 +532,24 @@ class UploadFoundation extends _foundation.default {
|
|
|
492
532
|
/* istanbul ignore next */
|
|
493
533
|
manualUpload() {
|
|
494
534
|
// find the list of files that have not been uploaded
|
|
495
|
-
const waitToUploadFileList = this.
|
|
535
|
+
const waitToUploadFileList = this.getLatestFileList().filter(item => item.status === FILE_STATUS_WAIT_UPLOAD);
|
|
496
536
|
this.startUpload(waitToUploadFileList);
|
|
497
537
|
}
|
|
498
538
|
startUpload(fileList) {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
539
|
+
// Seed a working copy so multiple synchronous beforeUpload results
|
|
540
|
+
// (e.g. several files returning autoRemove) compose correctly instead of each
|
|
541
|
+
// reading a stale React state snapshot and overwriting earlier removals. (#3335)
|
|
542
|
+
// try/finally guarantees the working copy is cleared even if beforeUpload throws.
|
|
543
|
+
this._batchFileList = this.getLatestFileList().slice();
|
|
544
|
+
try {
|
|
545
|
+
fileList.forEach(file => {
|
|
546
|
+
if (!file._sizeInvalid) {
|
|
547
|
+
this.upload(file);
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
} finally {
|
|
551
|
+
this._batchFileList = null;
|
|
552
|
+
}
|
|
504
553
|
}
|
|
505
554
|
upload(file) {
|
|
506
555
|
const {
|
|
@@ -511,9 +560,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
511
560
|
return;
|
|
512
561
|
}
|
|
513
562
|
if (typeof beforeUpload === 'function') {
|
|
514
|
-
const
|
|
515
|
-
fileList
|
|
516
|
-
} = this.getStates();
|
|
563
|
+
const fileList = this.getLatestFileList();
|
|
517
564
|
const buResult = this._adapter.notifyBeforeUpload({
|
|
518
565
|
file,
|
|
519
566
|
fileList
|
|
@@ -578,7 +625,11 @@ class UploadFoundation extends _foundation.default {
|
|
|
578
625
|
validateMessage,
|
|
579
626
|
fileInstance
|
|
580
627
|
} = buResult;
|
|
581
|
-
|
|
628
|
+
// During a synchronous startUpload batch, read from the working copy; for async
|
|
629
|
+
// (promise) results read from the most recent synchronous snapshot, falling back
|
|
630
|
+
// to React state. This keeps mixed sync + async beforeUpload results composing
|
|
631
|
+
// correctly under React 18 automatic batching. (#3335)
|
|
632
|
+
let newFileList = this.getLatestFileList().slice();
|
|
582
633
|
if (autoRemove) {
|
|
583
634
|
this._releaseFileUrl(file.uid);
|
|
584
635
|
newFileList = newFileList.filter(item => item.uid !== file.uid);
|
|
@@ -600,7 +651,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
600
651
|
}
|
|
601
652
|
newFileList[index].shouldUpload = shouldUpload;
|
|
602
653
|
}
|
|
603
|
-
this.
|
|
654
|
+
this.updateFileListInternal(newFileList);
|
|
604
655
|
this._adapter.notifyChange({
|
|
605
656
|
fileList: newFileList,
|
|
606
657
|
currentFile: file
|
|
@@ -714,10 +765,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
714
765
|
e,
|
|
715
766
|
fileInstance
|
|
716
767
|
} = _ref2;
|
|
717
|
-
const
|
|
718
|
-
fileList
|
|
719
|
-
} = this.getStates();
|
|
720
|
-
const newFileList = fileList.slice();
|
|
768
|
+
const newFileList = this.getLatestFileList().slice();
|
|
721
769
|
let percent = 0;
|
|
722
770
|
if (e.total > 0) {
|
|
723
771
|
percent = Number((e.loaded / e.total * 100 * _constants.numbers.PROGRESS_COEFFICIENT).toFixed(0)) || 0;
|
|
@@ -729,7 +777,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
729
777
|
newFileList[index].percent = percent;
|
|
730
778
|
newFileList[index].status = FILE_STATUS_UPLOADING;
|
|
731
779
|
this._adapter.notifyProgress(percent, fileInstance, newFileList);
|
|
732
|
-
this.
|
|
780
|
+
this.updateFileListInternal(newFileList);
|
|
733
781
|
this._adapter.notifyChange({
|
|
734
782
|
fileList: newFileList,
|
|
735
783
|
currentFile: newFileList[index]
|
|
@@ -741,9 +789,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
741
789
|
xhr,
|
|
742
790
|
fileInstance
|
|
743
791
|
} = _ref3;
|
|
744
|
-
const
|
|
745
|
-
fileList
|
|
746
|
-
} = this.getStates();
|
|
792
|
+
const fileList = this.getLatestFileList();
|
|
747
793
|
const index = this._getFileIndex(fileInstance, fileList);
|
|
748
794
|
if (index < 0) {
|
|
749
795
|
return;
|
|
@@ -771,9 +817,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
771
817
|
xhr,
|
|
772
818
|
response
|
|
773
819
|
} = _ref4;
|
|
774
|
-
const
|
|
775
|
-
fileList
|
|
776
|
-
} = this.getStates();
|
|
820
|
+
const fileList = this.getLatestFileList();
|
|
777
821
|
let body = null;
|
|
778
822
|
const index = this._getFileIndex(fileInstance, fileList);
|
|
779
823
|
if (index < 0) {
|
|
@@ -824,7 +868,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
824
868
|
fileList: newFileList,
|
|
825
869
|
currentFile: newFileList[index]
|
|
826
870
|
});
|
|
827
|
-
this.
|
|
871
|
+
this.updateFileListInternal(newFileList);
|
|
828
872
|
}
|
|
829
873
|
_getFileIndex(file, fileList) {
|
|
830
874
|
return fileList.findIndex(item => item.uid === file.uid);
|
|
@@ -852,7 +896,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
852
896
|
newFileList.splice(index, 1);
|
|
853
897
|
this._releaseFileUrl(file.uid);
|
|
854
898
|
this._adapter.notifyRemove(file.fileInstance, newFileList, file);
|
|
855
|
-
this.
|
|
899
|
+
this.updateFileListInternal(newFileList);
|
|
856
900
|
this._adapter.notifyChange({
|
|
857
901
|
fileList: newFileList,
|
|
858
902
|
currentFile: file
|
|
@@ -865,9 +909,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
865
909
|
xhr,
|
|
866
910
|
fileInstance
|
|
867
911
|
} = _ref5;
|
|
868
|
-
const
|
|
869
|
-
fileList
|
|
870
|
-
} = this.getStates();
|
|
912
|
+
const fileList = this.getLatestFileList();
|
|
871
913
|
const index = this._getFileIndex(fileInstance, fileList);
|
|
872
914
|
if (index < 0) {
|
|
873
915
|
return;
|
|
@@ -885,7 +927,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
885
927
|
newFileList[index].response = error;
|
|
886
928
|
newFileList[index].event = e;
|
|
887
929
|
this._adapter.notifyError(error, fileInstance, newFileList, xhr);
|
|
888
|
-
this.
|
|
930
|
+
this.updateFileListInternal(newFileList);
|
|
889
931
|
this._adapter.notifyChange({
|
|
890
932
|
currentFile: newFileList[index],
|
|
891
933
|
fileList: newFileList
|
|
@@ -906,7 +948,7 @@ class UploadFoundation extends _foundation.default {
|
|
|
906
948
|
return;
|
|
907
949
|
}
|
|
908
950
|
this._releaseAllFileUrls();
|
|
909
|
-
this.
|
|
951
|
+
this.updateFileListInternal([]);
|
|
910
952
|
this._adapter.notifyClear();
|
|
911
953
|
this._adapter.notifyChange({
|
|
912
954
|
fileList: []
|
package/lib/es/button/button.css
CHANGED
|
@@ -19,6 +19,7 @@ $module: #{$prefix}-button;
|
|
|
19
19
|
padding-right: $spacing-button_default-paddingRight;
|
|
20
20
|
padding-top: $spacing-button_default-paddingTop;
|
|
21
21
|
padding-bottom: $spacing-button_default-paddingTop;
|
|
22
|
+
font-family: inherit;
|
|
22
23
|
font-size: $font-button-fontSize;
|
|
23
24
|
line-height: $font-button-lineHeight;
|
|
24
25
|
font-weight: $font-button-fontWeight;
|