@douyinfe/semi-foundation 2.96.0 → 2.97.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/cascader/foundation.ts +74 -19
- package/datePicker/datePicker.scss +100 -5
- package/form/foundation.ts +7 -3
- package/form/utils.ts +7 -2
- package/image/previewImageFoundation.ts +34 -3
- package/image/previewInnerFoundation.ts +15 -4
- package/input/textarea.scss +35 -0
- package/lib/cjs/cascader/foundation.d.ts +12 -0
- package/lib/cjs/cascader/foundation.js +68 -23
- package/lib/cjs/datePicker/datePicker.css +67 -5
- package/lib/cjs/datePicker/datePicker.scss +100 -5
- package/lib/cjs/form/foundation.d.ts +1 -1
- package/lib/cjs/form/foundation.js +6 -6
- package/lib/cjs/form/utils.js +5 -2
- package/lib/cjs/image/previewImageFoundation.d.ts +4 -0
- package/lib/cjs/image/previewImageFoundation.js +33 -2
- package/lib/cjs/image/previewInnerFoundation.d.ts +1 -0
- package/lib/cjs/image/previewInnerFoundation.js +17 -4
- package/lib/cjs/input/textarea.css +17 -0
- package/lib/cjs/input/textarea.scss +35 -0
- package/lib/cjs/navigation/navigation.css +2 -1
- package/lib/cjs/navigation/navigation.scss +1 -0
- package/lib/cjs/navigation/variables.scss +1 -1
- package/lib/cjs/overflowList/foundation.d.ts +1 -0
- package/lib/cjs/overflowList/foundation.js +51 -1
- package/lib/cjs/select/foundation.d.ts +1 -1
- package/lib/cjs/select/foundation.js +28 -2
- package/lib/cjs/switch/switch.css +1 -0
- package/lib/cjs/switch/switch.scss +1 -0
- package/lib/cjs/switch/variables.scss +2 -1
- package/lib/cjs/table/foundation.js +2 -1
- package/lib/cjs/tag/tag.css +26 -0
- package/lib/cjs/tag/tag.scss +33 -0
- package/lib/cjs/tagInput/tagInput.css +17 -0
- package/lib/cjs/tagInput/tagInput.scss +18 -0
- package/lib/cjs/timePicker/constants.d.ts +1 -0
- package/lib/cjs/timePicker/foundation.d.ts +7 -1
- package/lib/cjs/timePicker/foundation.js +62 -11
- package/lib/es/cascader/foundation.d.ts +12 -0
- package/lib/es/cascader/foundation.js +68 -23
- package/lib/es/datePicker/datePicker.css +67 -5
- package/lib/es/datePicker/datePicker.scss +100 -5
- package/lib/es/form/foundation.d.ts +1 -1
- package/lib/es/form/foundation.js +6 -6
- package/lib/es/form/utils.js +5 -2
- package/lib/es/image/previewImageFoundation.d.ts +4 -0
- package/lib/es/image/previewImageFoundation.js +33 -2
- package/lib/es/image/previewInnerFoundation.d.ts +1 -0
- package/lib/es/image/previewInnerFoundation.js +17 -4
- package/lib/es/input/textarea.css +17 -0
- package/lib/es/input/textarea.scss +35 -0
- package/lib/es/navigation/navigation.css +2 -1
- package/lib/es/navigation/navigation.scss +1 -0
- package/lib/es/navigation/variables.scss +1 -1
- package/lib/es/overflowList/foundation.d.ts +1 -0
- package/lib/es/overflowList/foundation.js +51 -1
- package/lib/es/select/foundation.d.ts +1 -1
- package/lib/es/select/foundation.js +28 -2
- package/lib/es/switch/switch.css +1 -0
- package/lib/es/switch/switch.scss +1 -0
- package/lib/es/switch/variables.scss +2 -1
- package/lib/es/table/foundation.js +2 -1
- package/lib/es/tag/tag.css +26 -0
- package/lib/es/tag/tag.scss +33 -0
- package/lib/es/tagInput/tagInput.css +17 -0
- package/lib/es/tagInput/tagInput.scss +18 -0
- package/lib/es/timePicker/constants.d.ts +1 -0
- package/lib/es/timePicker/foundation.d.ts +7 -1
- package/lib/es/timePicker/foundation.js +62 -11
- package/navigation/navigation.scss +1 -0
- package/navigation/variables.scss +1 -1
- package/overflowList/foundation.ts +48 -2
- package/package.json +4 -4
- package/select/foundation.ts +27 -2
- package/switch/switch.scss +1 -0
- package/switch/variables.scss +2 -1
- package/table/foundation.ts +2 -1
- package/tag/tag.scss +33 -0
- package/tagInput/tagInput.scss +18 -0
- package/timePicker/constants.ts +2 -0
- package/timePicker/foundation.ts +62 -10
|
@@ -27,11 +27,21 @@ class OverflowListFoundation extends BaseFoundation {
|
|
|
27
27
|
} = this.getProps();
|
|
28
28
|
const {
|
|
29
29
|
visibleState,
|
|
30
|
-
overflow
|
|
30
|
+
overflow,
|
|
31
|
+
scrollOverflow
|
|
31
32
|
} = this.getStates();
|
|
32
33
|
if (!this.isScrollMode()) {
|
|
33
34
|
return overflow;
|
|
34
35
|
}
|
|
36
|
+
// Scroll mode relies on IntersectionObserver to compute visibility.
|
|
37
|
+
// During recalculation (e.g. items changed, or before observer fires),
|
|
38
|
+
// keep last computed overflow to avoid UI flicker (tabs arrows/menu state).
|
|
39
|
+
if (!visibleState || visibleState.size === 0) {
|
|
40
|
+
if (Array.isArray(scrollOverflow) && scrollOverflow.length === 2) {
|
|
41
|
+
return scrollOverflow;
|
|
42
|
+
}
|
|
43
|
+
return [[], []];
|
|
44
|
+
}
|
|
35
45
|
const visibleStateArr = items.map(_ref => {
|
|
36
46
|
let {
|
|
37
47
|
key
|
|
@@ -40,11 +50,49 @@ class OverflowListFoundation extends BaseFoundation {
|
|
|
40
50
|
});
|
|
41
51
|
const visibleStart = visibleStateArr.indexOf(true);
|
|
42
52
|
const visibleEnd = visibleStateArr.lastIndexOf(true);
|
|
53
|
+
// If no item is visible (e.g. initial layout not ready or list out of viewport),
|
|
54
|
+
// treat it as "unknown" and keep last computed overflow to avoid wrong enabling.
|
|
55
|
+
if (visibleStart < 0 || visibleEnd < 0) {
|
|
56
|
+
if (Array.isArray(scrollOverflow) && scrollOverflow.length === 2) {
|
|
57
|
+
return scrollOverflow;
|
|
58
|
+
}
|
|
59
|
+
return [[], []];
|
|
60
|
+
}
|
|
43
61
|
const overflowList = [];
|
|
44
62
|
overflowList[0] = visibleStart >= 0 ? items.slice(0, visibleStart) : [];
|
|
45
63
|
overflowList[1] = visibleEnd >= 0 ? items.slice(visibleEnd + 1, items.length) : items.slice();
|
|
46
64
|
return overflowList;
|
|
47
65
|
}
|
|
66
|
+
_syncScrollOverflowCache(nextVisibleState) {
|
|
67
|
+
if (!this.isScrollMode()) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const {
|
|
71
|
+
items
|
|
72
|
+
} = this.getProps();
|
|
73
|
+
const visibleStateArr = items.map(_ref2 => {
|
|
74
|
+
let {
|
|
75
|
+
key
|
|
76
|
+
} = _ref2;
|
|
77
|
+
return Boolean(nextVisibleState.get(key));
|
|
78
|
+
});
|
|
79
|
+
const visibleStart = visibleStateArr.indexOf(true);
|
|
80
|
+
const visibleEnd = visibleStateArr.lastIndexOf(true);
|
|
81
|
+
// No visible items means the result is not reliable; keep cache and stay "calculating"
|
|
82
|
+
if (visibleStart < 0 || visibleEnd < 0) {
|
|
83
|
+
this._adapter.updateStates({
|
|
84
|
+
isScrollOverflowCalculating: true
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const overflowList = [];
|
|
89
|
+
overflowList[0] = visibleStart >= 0 ? items.slice(0, visibleStart) : [];
|
|
90
|
+
overflowList[1] = visibleEnd >= 0 ? items.slice(visibleEnd + 1, items.length) : items.slice();
|
|
91
|
+
this._adapter.updateStates({
|
|
92
|
+
scrollOverflow: overflowList,
|
|
93
|
+
isScrollOverflowCalculating: false
|
|
94
|
+
});
|
|
95
|
+
}
|
|
48
96
|
handleIntersect(entries) {
|
|
49
97
|
const visibleState = copy(this.getState('visibleState'));
|
|
50
98
|
const res = {};
|
|
@@ -73,6 +121,8 @@ class OverflowListFoundation extends BaseFoundation {
|
|
|
73
121
|
}
|
|
74
122
|
this.previousY = currentY;
|
|
75
123
|
this._adapter.updateVisibleState(visibleState);
|
|
124
|
+
// Keep scroll overflow cache in sync for stable UI
|
|
125
|
+
this._syncScrollOverflowCache(visibleState);
|
|
76
126
|
this._adapter.notifyIntersect(res);
|
|
77
127
|
}
|
|
78
128
|
handleCollapseOverflow() {
|
|
@@ -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(optionsForOpen?: BasicOptionProps[]): void;
|
|
57
|
+
focus(optionsForOpen?: BasicOptionProps[], openDropdown?: boolean): void;
|
|
58
58
|
_focusTrigger(): void;
|
|
59
59
|
destroy(): void;
|
|
60
60
|
_setDropdownWidth(): void;
|
|
@@ -37,15 +37,40 @@ export default class SelectFoundation extends BaseFoundation {
|
|
|
37
37
|
this.focus(originalOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
focus(optionsForOpen) {
|
|
40
|
+
focus(optionsForOpen, openDropdown) {
|
|
41
41
|
const isFilterable = this._isFilterable();
|
|
42
42
|
const isMultiple = this._isMultiple();
|
|
43
43
|
const {
|
|
44
44
|
isOpen
|
|
45
45
|
} = this.getStates();
|
|
46
|
+
const {
|
|
47
|
+
searchPosition
|
|
48
|
+
} = this.getProps();
|
|
49
|
+
// Default to true if not specified (backward compatibility)
|
|
50
|
+
const shouldOpenDropdown = openDropdown !== false;
|
|
46
51
|
this._adapter.updateFocusState(true);
|
|
47
52
|
this._adapter.setIsFocusInContainer(false);
|
|
48
53
|
if (isFilterable) {
|
|
54
|
+
/**
|
|
55
|
+
* When openDropdown is false, we only want to "refocus" the Select
|
|
56
|
+
* without changing dropdown visibility.
|
|
57
|
+
*
|
|
58
|
+
* NOTE: For searchPosition='dropdown', the search input is rendered in dropdown,
|
|
59
|
+
* so we should NOT toggle trigger input(showInput) here, otherwise it may affect
|
|
60
|
+
* tabIndex / focusability unexpectedly.
|
|
61
|
+
*/
|
|
62
|
+
if (!shouldOpenDropdown) {
|
|
63
|
+
if (searchPosition === strings.SEARCH_POSITION_TRIGGER) {
|
|
64
|
+
if (isMultiple) {
|
|
65
|
+
this.focusInput();
|
|
66
|
+
} else {
|
|
67
|
+
this.toggle2SearchInput(true);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
this._focusTrigger();
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
49
74
|
if (isMultiple) {
|
|
50
75
|
// when filter and multiple, focus input and open dropdown
|
|
51
76
|
this.focusInput();
|
|
@@ -1083,7 +1108,8 @@ export default class SelectFoundation extends BaseFoundation {
|
|
|
1083
1108
|
this.clearInput(e);
|
|
1084
1109
|
}
|
|
1085
1110
|
// after click showClear button, the select need to be focused
|
|
1086
|
-
|
|
1111
|
+
// but don't open dropdown to avoid focus state confusion
|
|
1112
|
+
this.focus(undefined, false);
|
|
1087
1113
|
this.clearSelected();
|
|
1088
1114
|
// prevent this click open dropdown
|
|
1089
1115
|
e.stopPropagation();
|
package/lib/es/switch/switch.css
CHANGED
|
@@ -30,7 +30,8 @@ $color-switch_disabled-border-default: var(--semi-color-border); // 禁用态开
|
|
|
30
30
|
$color-switch_disabled-bg-hover: transparent; // 禁用态开关背景色 - 悬浮
|
|
31
31
|
$color-switch_checked_disabled-bg-default: var(--semi-color-success-disabled); // 禁用开启态开关背景颜色
|
|
32
32
|
$color-switch_checked_disabled-border-default: transparent; // 禁用开启态开关描边颜色
|
|
33
|
-
$color-switch_knob-bg-default: rgba(var(--semi-white), 1); // 开关滑块背景颜色
|
|
33
|
+
$color-switch_knob-bg-default: rgba(var(--semi-white), 1); // 开关滑块背景颜色 - 关闭态
|
|
34
|
+
$color-switch_knob-bg-checked: rgba(var(--semi-white), 1); // 开关滑块背景颜色 - 开启态
|
|
34
35
|
$color-switch_knob-border-default: var(--semi-color-border); // 开关滑块描边颜色
|
|
35
36
|
$color-switch_checked-text-default: var(--semi-color-white); // 开启态开关文案颜色
|
|
36
37
|
$color-switch_unchecked-text-default: var(--semi-color-text-2); // 关闭态开关文案颜色
|
|
@@ -881,7 +881,8 @@ class TableFoundation extends BaseFoundation {
|
|
|
881
881
|
let e = arguments.length > 1 ? arguments[1] : undefined;
|
|
882
882
|
let check = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
883
883
|
var _a, _b, _c, _d;
|
|
884
|
-
|
|
884
|
+
/* Do not call stopPropagation here, otherwise the click event registered via onHeaderCell
|
|
885
|
+
will be blocked when the click hot area is the whole title (#1861). */
|
|
885
886
|
/* if mouse down to the resizable handle, do not trigger the sorting,fix #2802
|
|
886
887
|
The target of the click event may be different from the target of the mousedown,
|
|
887
888
|
e.g: Press the mouse, move to another node and then release it,
|
package/lib/es/tag/tag.css
CHANGED
|
@@ -505,6 +505,32 @@
|
|
|
505
505
|
color: var(--semi-color-text-0);
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
+
.semi-tag-split {
|
|
509
|
+
display: inline-flex;
|
|
510
|
+
align-items: center;
|
|
511
|
+
}
|
|
512
|
+
.semi-tag-split .semi-tag {
|
|
513
|
+
border-radius: 0;
|
|
514
|
+
margin-right: 1px;
|
|
515
|
+
}
|
|
516
|
+
.semi-tag-split .semi-tag-first {
|
|
517
|
+
border-top-left-radius: var(--semi-border-radius-small);
|
|
518
|
+
border-bottom-left-radius: var(--semi-border-radius-small);
|
|
519
|
+
}
|
|
520
|
+
.semi-tag-split .semi-tag-last {
|
|
521
|
+
border-top-right-radius: var(--semi-border-radius-small);
|
|
522
|
+
border-bottom-right-radius: var(--semi-border-radius-small);
|
|
523
|
+
margin-right: unset;
|
|
524
|
+
}
|
|
525
|
+
.semi-tag-split .semi-tag-circle.semi-tag-first {
|
|
526
|
+
border-top-left-radius: var(--semi-border-radius-full);
|
|
527
|
+
border-bottom-left-radius: var(--semi-border-radius-full);
|
|
528
|
+
}
|
|
529
|
+
.semi-tag-split .semi-tag-circle.semi-tag-last {
|
|
530
|
+
border-top-right-radius: var(--semi-border-radius-full);
|
|
531
|
+
border-bottom-right-radius: var(--semi-border-radius-full);
|
|
532
|
+
}
|
|
533
|
+
|
|
508
534
|
.semi-rtl .semi-tag,
|
|
509
535
|
.semi-portal-rtl .semi-tag {
|
|
510
536
|
direction: rtl;
|
package/lib/es/tag/tag.scss
CHANGED
|
@@ -329,4 +329,37 @@ $types: "ghost", "solid", "light";
|
|
|
329
329
|
color: $color-tag_avatar-text-default;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
.#{$module}-split {
|
|
333
|
+
display: inline-flex;
|
|
334
|
+
align-items: center;
|
|
335
|
+
|
|
336
|
+
.#{$module} {
|
|
337
|
+
border-radius: 0;
|
|
338
|
+
margin-right: 1px;
|
|
339
|
+
|
|
340
|
+
&-first {
|
|
341
|
+
border-top-left-radius: $radius-tag;
|
|
342
|
+
border-bottom-left-radius: $radius-tag;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
&-last {
|
|
346
|
+
border-top-right-radius: $radius-tag;
|
|
347
|
+
border-bottom-right-radius: $radius-tag;
|
|
348
|
+
margin-right: unset;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
&-circle {
|
|
352
|
+
&.#{$module}-first {
|
|
353
|
+
border-top-left-radius: $radius-tag_circle;
|
|
354
|
+
border-bottom-left-radius: $radius-tag_circle;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
&.#{$module}-last {
|
|
358
|
+
border-top-right-radius: $radius-tag_circle;
|
|
359
|
+
border-bottom-right-radius: $radius-tag_circle;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
332
365
|
@import './rtl.scss';
|
|
@@ -112,6 +112,8 @@
|
|
|
112
112
|
padding-left: 4px;
|
|
113
113
|
padding-right: 4px;
|
|
114
114
|
overflow: hidden;
|
|
115
|
+
position: relative;
|
|
116
|
+
/* hidden mirror used to measure input text width */
|
|
115
117
|
}
|
|
116
118
|
.semi-tagInput-wrapper-tag {
|
|
117
119
|
margin-right: 4px;
|
|
@@ -154,6 +156,8 @@
|
|
|
154
156
|
.semi-tagInput-wrapper .semi-tagInput-wrapper-input {
|
|
155
157
|
flex-grow: 1;
|
|
156
158
|
width: min-content;
|
|
159
|
+
min-width: 2px;
|
|
160
|
+
max-width: 100%;
|
|
157
161
|
border: none;
|
|
158
162
|
outline: none;
|
|
159
163
|
background-color: transparent;
|
|
@@ -195,6 +199,19 @@
|
|
|
195
199
|
height: 24px;
|
|
196
200
|
line-height: 24px;
|
|
197
201
|
}
|
|
202
|
+
.semi-tagInput-wrapper-inputMirror {
|
|
203
|
+
position: absolute;
|
|
204
|
+
top: 0;
|
|
205
|
+
left: 0;
|
|
206
|
+
visibility: hidden;
|
|
207
|
+
pointer-events: none;
|
|
208
|
+
height: 0;
|
|
209
|
+
overflow: hidden;
|
|
210
|
+
white-space: pre;
|
|
211
|
+
font-size: 14px;
|
|
212
|
+
font-weight: 400;
|
|
213
|
+
font-family: inherit;
|
|
214
|
+
}
|
|
198
215
|
.semi-tagInput-clearBtn {
|
|
199
216
|
display: flex;
|
|
200
217
|
justify-content: center;
|
|
@@ -137,6 +137,7 @@ $module: #{$prefix}-tagInput;
|
|
|
137
137
|
padding-left: $spacing-extra-tight;
|
|
138
138
|
padding-right: $spacing-extra-tight;
|
|
139
139
|
overflow: hidden;
|
|
140
|
+
position: relative;
|
|
140
141
|
|
|
141
142
|
&-tag {
|
|
142
143
|
margin-right: $spacing-extra-tight;
|
|
@@ -190,6 +191,8 @@ $module: #{$prefix}-tagInput;
|
|
|
190
191
|
& &-input {
|
|
191
192
|
flex-grow: 1;
|
|
192
193
|
width: min-content;
|
|
194
|
+
min-width: 2px;
|
|
195
|
+
max-width: 100%;
|
|
193
196
|
// min-width: 38px;
|
|
194
197
|
border: none;
|
|
195
198
|
outline: none;
|
|
@@ -240,6 +243,21 @@ $module: #{$prefix}-tagInput;
|
|
|
240
243
|
}
|
|
241
244
|
}
|
|
242
245
|
}
|
|
246
|
+
|
|
247
|
+
/* hidden mirror used to measure input text width */
|
|
248
|
+
&-inputMirror {
|
|
249
|
+
position: absolute;
|
|
250
|
+
top: 0;
|
|
251
|
+
left: 0;
|
|
252
|
+
visibility: hidden;
|
|
253
|
+
pointer-events: none;
|
|
254
|
+
height: 0;
|
|
255
|
+
overflow: hidden;
|
|
256
|
+
white-space: pre;
|
|
257
|
+
font-size: $font-size-regular;
|
|
258
|
+
font-weight: $font-weight-regular;
|
|
259
|
+
font-family: inherit;
|
|
260
|
+
}
|
|
243
261
|
}
|
|
244
262
|
|
|
245
263
|
&-clearBtn {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PanelType } from './constants';
|
|
1
2
|
import BaseFoundation, { DefaultAdapter } from '../base/foundation';
|
|
2
3
|
export type Position = 'top' | 'topLeft' | 'topRight' | 'left' | 'leftTop' | 'leftBottom' | 'right' | 'rightTop' | 'rightBottom' | 'bottom' | 'bottomLeft' | 'bottomRight' | 'leftTopOver' | 'rightTopOver';
|
|
3
4
|
export interface TimePickerAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
|
|
@@ -16,11 +17,16 @@ declare class TimePickerFoundation<P = Record<string, any>, S = Record<string, a
|
|
|
16
17
|
constructor(adapter: TimePickerAdapter<P, S>);
|
|
17
18
|
init(): void;
|
|
18
19
|
getPosition(): Position;
|
|
20
|
+
getDisabledTimeFns(panelType: PanelType, dates: Date[]): {
|
|
21
|
+
disabledHours: any;
|
|
22
|
+
disabledMinutes: any;
|
|
23
|
+
disabledSeconds: any;
|
|
24
|
+
};
|
|
19
25
|
isDisabledHMS({ hours, minutes, seconds }: {
|
|
20
26
|
hours: number;
|
|
21
27
|
minutes: number;
|
|
22
28
|
seconds: number;
|
|
23
|
-
}): boolean;
|
|
29
|
+
}, panelType?: PanelType, dates?: Date[]): boolean;
|
|
24
30
|
isValidTimeZone(timeZone: string | number): boolean;
|
|
25
31
|
getDefaultFormatIfNeed(): string;
|
|
26
32
|
/**
|
|
@@ -26,17 +26,44 @@ class TimePickerFoundation extends BaseFoundation {
|
|
|
26
26
|
const rtlDirection = direction === 'rtl' ? 'bottomRight' : '';
|
|
27
27
|
return position || rtlDirection || strings.DEFAULT_POSITION[type];
|
|
28
28
|
}
|
|
29
|
+
getDisabledTimeFns(panelType, dates) {
|
|
30
|
+
const {
|
|
31
|
+
disabledHours,
|
|
32
|
+
disabledMinutes,
|
|
33
|
+
disabledSeconds,
|
|
34
|
+
disabledTime
|
|
35
|
+
} = this.getProps();
|
|
36
|
+
// disabledTime is range-only: only invoke it when the picker is
|
|
37
|
+
// actually a range picker. In single mode panelType has no meaning, so
|
|
38
|
+
// we fall back to the top-level disabledHours / disabledMinutes /
|
|
39
|
+
// disabledSeconds without invoking disabledTime.
|
|
40
|
+
if (typeof disabledTime === 'function' && this._adapter.isRangePicker()) {
|
|
41
|
+
const disabledObj = disabledTime(dates, panelType) || {};
|
|
42
|
+
return {
|
|
43
|
+
disabledHours: disabledObj.disabledHours || disabledHours,
|
|
44
|
+
disabledMinutes: disabledObj.disabledMinutes || disabledMinutes,
|
|
45
|
+
disabledSeconds: disabledObj.disabledSeconds || disabledSeconds
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
disabledHours,
|
|
50
|
+
disabledMinutes,
|
|
51
|
+
disabledSeconds
|
|
52
|
+
};
|
|
53
|
+
}
|
|
29
54
|
isDisabledHMS(_ref) {
|
|
30
55
|
let {
|
|
31
56
|
hours,
|
|
32
57
|
minutes,
|
|
33
58
|
seconds
|
|
34
59
|
} = _ref;
|
|
60
|
+
let panelType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'left';
|
|
61
|
+
let dates = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
|
35
62
|
const {
|
|
36
63
|
disabledHours,
|
|
37
64
|
disabledMinutes,
|
|
38
65
|
disabledSeconds
|
|
39
|
-
} = this.
|
|
66
|
+
} = this.getDisabledTimeFns(panelType, dates);
|
|
40
67
|
const hDis = !isNullOrUndefined(hours) && hourIsDisabled(disabledHours, hours);
|
|
41
68
|
const mDis = !isNullOrUndefined(hours) && !isNullOrUndefined(minutes) && minuteIsDisabled(disabledMinutes, hours, minutes);
|
|
42
69
|
const sDis = !isNullOrUndefined(hours) && !isNullOrUndefined(minutes) && !isNullOrUndefined(seconds) && secondIsDisabled(disabledSeconds, hours, minutes, seconds);
|
|
@@ -158,11 +185,23 @@ class TimePickerFoundation extends BaseFoundation {
|
|
|
158
185
|
if (this.isValidTimeZone(timeZone)) {
|
|
159
186
|
dates = dates.map(date => utcToZonedTime(this.isValidTimeZone(__prevTimeZone) ? zonedTimeToUtc(date, __prevTimeZone) : date, timeZone));
|
|
160
187
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
188
|
+
if (this._adapter.isRangePicker()) {
|
|
189
|
+
invalid = dates.some((d, idx) => {
|
|
190
|
+
const panelType = idx === 1 ? 'right' : 'left';
|
|
191
|
+
return this.isDisabledHMS({
|
|
192
|
+
hours: d.getHours(),
|
|
193
|
+
minutes: d.getMinutes(),
|
|
194
|
+
seconds: d.getSeconds()
|
|
195
|
+
}, panelType, dates);
|
|
196
|
+
});
|
|
197
|
+
} else {
|
|
198
|
+
const d = dates[0];
|
|
199
|
+
invalid = d ? this.isDisabledHMS({
|
|
200
|
+
hours: d.getHours(),
|
|
201
|
+
minutes: d.getMinutes(),
|
|
202
|
+
seconds: d.getSeconds()
|
|
203
|
+
}, 'left', dates) : false;
|
|
204
|
+
}
|
|
166
205
|
}
|
|
167
206
|
const inputValue = this.formatValue(dates);
|
|
168
207
|
this.setState({
|
|
@@ -258,11 +297,23 @@ class TimePickerFoundation extends BaseFoundation {
|
|
|
258
297
|
let dates = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
259
298
|
let invalid = dates.some(d => isNaN(Number(d)));
|
|
260
299
|
if (!invalid) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
300
|
+
if (this._adapter.isRangePicker()) {
|
|
301
|
+
invalid = dates.some((d, idx) => {
|
|
302
|
+
const panelType = idx === 1 ? 'right' : 'left';
|
|
303
|
+
return this.isDisabledHMS({
|
|
304
|
+
hours: d.getHours(),
|
|
305
|
+
minutes: d.getMinutes(),
|
|
306
|
+
seconds: d.getSeconds()
|
|
307
|
+
}, panelType, dates);
|
|
308
|
+
});
|
|
309
|
+
} else {
|
|
310
|
+
const d = dates[0];
|
|
311
|
+
invalid = d ? this.isDisabledHMS({
|
|
312
|
+
hours: d.getHours(),
|
|
313
|
+
minutes: d.getMinutes(),
|
|
314
|
+
seconds: d.getSeconds()
|
|
315
|
+
}, 'left', dates) : false;
|
|
316
|
+
}
|
|
266
317
|
}
|
|
267
318
|
return invalid;
|
|
268
319
|
}
|
|
@@ -569,6 +569,7 @@ $module: #{$prefix}-navigation;
|
|
|
569
569
|
& > .#{$prefix}-button {
|
|
570
570
|
padding-left: $spacing-navigation_footer_collapse_btn_inner-paddingX;
|
|
571
571
|
padding-right: $spacing-navigation_footer_collapse_btn_inner-paddingX;
|
|
572
|
+
color: $color-navigation_footer_icon-default;
|
|
572
573
|
}
|
|
573
574
|
}
|
|
574
575
|
|
|
@@ -65,7 +65,7 @@ $spacing-navigation_sub_item_left_toggle_marginRight:$spacing-tight; // 顶部
|
|
|
65
65
|
$color-navigation-bg-default: var(--semi-color-nav-bg); // 导航栏背景色
|
|
66
66
|
$color-navigation_border-default: var(--semi-color-border); // 导航栏分割线色
|
|
67
67
|
$color-navigation_header-text-default: var(--semi-color-text-0); // 导航栏 header 文字颜色
|
|
68
|
-
$color-navigation_footer_icon-default: var(--semi-color-text-
|
|
68
|
+
$color-navigation_footer_icon-default: var(--semi-color-text-1); // 导航栏 footer 图标颜色
|
|
69
69
|
$color-navigation_itemL1-bg-default: transparent; // 导航栏一级菜单项背景色
|
|
70
70
|
$color-navigation_itemL1-text-default: var(--semi-color-text-0); // 导航栏一级菜单项文字颜色
|
|
71
71
|
$color-navigation_itemL1_icon-default: var(--semi-color-text-2); // 导航栏一级菜单项图标颜色
|
|
@@ -28,22 +28,66 @@ class OverflowListFoundation extends BaseFoundation<OverflowListAdapter> {
|
|
|
28
28
|
|
|
29
29
|
getOverflowItem(): Array<Array<Record<string, any>>> {
|
|
30
30
|
const { items } = this.getProps();
|
|
31
|
-
const { visibleState, overflow } = this.getStates();
|
|
31
|
+
const { visibleState, overflow, scrollOverflow } = this.getStates();
|
|
32
32
|
if (!this.isScrollMode()) {
|
|
33
33
|
return overflow;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Scroll mode relies on IntersectionObserver to compute visibility.
|
|
37
|
+
// During recalculation (e.g. items changed, or before observer fires),
|
|
38
|
+
// keep last computed overflow to avoid UI flicker (tabs arrows/menu state).
|
|
39
|
+
if (!visibleState || visibleState.size === 0) {
|
|
40
|
+
if (Array.isArray(scrollOverflow) && scrollOverflow.length === 2) {
|
|
41
|
+
return scrollOverflow;
|
|
42
|
+
}
|
|
43
|
+
return [[], []];
|
|
44
|
+
}
|
|
36
45
|
|
|
37
46
|
const visibleStateArr = items.map(({ key }: { key: string }) => Boolean(visibleState.get(key)));
|
|
38
47
|
const visibleStart = visibleStateArr.indexOf(true);
|
|
39
48
|
const visibleEnd = visibleStateArr.lastIndexOf(true);
|
|
40
49
|
|
|
50
|
+
// If no item is visible (e.g. initial layout not ready or list out of viewport),
|
|
51
|
+
// treat it as "unknown" and keep last computed overflow to avoid wrong enabling.
|
|
52
|
+
if (visibleStart < 0 || visibleEnd < 0) {
|
|
53
|
+
if (Array.isArray(scrollOverflow) && scrollOverflow.length === 2) {
|
|
54
|
+
return scrollOverflow;
|
|
55
|
+
}
|
|
56
|
+
return [[], []];
|
|
57
|
+
}
|
|
58
|
+
|
|
41
59
|
const overflowList = [];
|
|
42
60
|
overflowList[0] = visibleStart >= 0 ? items.slice(0, visibleStart) : [];
|
|
43
61
|
overflowList[1] = visibleEnd >= 0 ? items.slice(visibleEnd + 1, items.length) : items.slice();
|
|
44
62
|
return overflowList;
|
|
45
63
|
}
|
|
46
64
|
|
|
65
|
+
private _syncScrollOverflowCache(nextVisibleState: Map<string, boolean>): void {
|
|
66
|
+
if (!this.isScrollMode()) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const { items } = this.getProps();
|
|
70
|
+
const visibleStateArr = items.map(({ key }: { key: string }) => Boolean(nextVisibleState.get(key)));
|
|
71
|
+
const visibleStart = visibleStateArr.indexOf(true);
|
|
72
|
+
const visibleEnd = visibleStateArr.lastIndexOf(true);
|
|
73
|
+
|
|
74
|
+
// No visible items means the result is not reliable; keep cache and stay "calculating"
|
|
75
|
+
if (visibleStart < 0 || visibleEnd < 0) {
|
|
76
|
+
this._adapter.updateStates({
|
|
77
|
+
isScrollOverflowCalculating: true,
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const overflowList: Array<Array<Record<string, any>>> = [];
|
|
83
|
+
overflowList[0] = visibleStart >= 0 ? items.slice(0, visibleStart) : [];
|
|
84
|
+
overflowList[1] = visibleEnd >= 0 ? items.slice(visibleEnd + 1, items.length) : items.slice();
|
|
85
|
+
this._adapter.updateStates({
|
|
86
|
+
scrollOverflow: overflowList,
|
|
87
|
+
isScrollOverflowCalculating: false,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
47
91
|
handleIntersect(entries: Array<IntersectionObserverEntry>): void {
|
|
48
92
|
const visibleState = copy(this.getState('visibleState'));
|
|
49
93
|
|
|
@@ -73,6 +117,8 @@ class OverflowListFoundation extends BaseFoundation<OverflowListAdapter> {
|
|
|
73
117
|
}
|
|
74
118
|
this.previousY = currentY;
|
|
75
119
|
this._adapter.updateVisibleState(visibleState);
|
|
120
|
+
// Keep scroll overflow cache in sync for stable UI
|
|
121
|
+
this._syncScrollOverflowCache(visibleState);
|
|
76
122
|
this._adapter.notifyIntersect(res);
|
|
77
123
|
}
|
|
78
124
|
|
|
@@ -126,4 +172,4 @@ class OverflowListFoundation extends BaseFoundation<OverflowListAdapter> {
|
|
|
126
172
|
|
|
127
173
|
}
|
|
128
174
|
|
|
129
|
-
export default OverflowListFoundation;
|
|
175
|
+
export default OverflowListFoundation;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@douyinfe/semi-foundation",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.97.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"clean": "rimraf lib",
|
|
@@ -14210,8 +14210,8 @@
|
|
|
14210
14210
|
}
|
|
14211
14211
|
},
|
|
14212
14212
|
"dependencies": {
|
|
14213
|
-
"@douyinfe/semi-animation": "2.
|
|
14214
|
-
"@douyinfe/semi-json-viewer-core": "2.
|
|
14213
|
+
"@douyinfe/semi-animation": "2.97.0",
|
|
14214
|
+
"@douyinfe/semi-json-viewer-core": "2.97.0",
|
|
14215
14215
|
"@mdx-js/mdx": "^3.0.1",
|
|
14216
14216
|
"async-validator": "^3.5.0",
|
|
14217
14217
|
"classnames": "^2.2.6",
|
|
@@ -14232,7 +14232,7 @@
|
|
|
14232
14232
|
"*.scss",
|
|
14233
14233
|
"*.css"
|
|
14234
14234
|
],
|
|
14235
|
-
"gitHead": "
|
|
14235
|
+
"gitHead": "fefc4b3e8ea823bc99f68bfee02f3f8cc314726c",
|
|
14236
14236
|
"devDependencies": {
|
|
14237
14237
|
"@babel/plugin-transform-runtime": "^7.15.8",
|
|
14238
14238
|
"@babel/preset-env": "^7.15.8",
|
package/select/foundation.ts
CHANGED
|
@@ -85,15 +85,39 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
focus(optionsForOpen?: BasicOptionProps[]) {
|
|
88
|
+
focus(optionsForOpen?: BasicOptionProps[], openDropdown?: boolean) {
|
|
89
89
|
const isFilterable = this._isFilterable();
|
|
90
90
|
const isMultiple = this._isMultiple();
|
|
91
91
|
const { isOpen } = this.getStates();
|
|
92
|
+
const { searchPosition } = this.getProps();
|
|
93
|
+
// Default to true if not specified (backward compatibility)
|
|
94
|
+
const shouldOpenDropdown = openDropdown !== false;
|
|
92
95
|
|
|
93
96
|
this._adapter.updateFocusState(true);
|
|
94
97
|
this._adapter.setIsFocusInContainer(false);
|
|
95
98
|
|
|
96
99
|
if (isFilterable) {
|
|
100
|
+
/**
|
|
101
|
+
* When openDropdown is false, we only want to "refocus" the Select
|
|
102
|
+
* without changing dropdown visibility.
|
|
103
|
+
*
|
|
104
|
+
* NOTE: For searchPosition='dropdown', the search input is rendered in dropdown,
|
|
105
|
+
* so we should NOT toggle trigger input(showInput) here, otherwise it may affect
|
|
106
|
+
* tabIndex / focusability unexpectedly.
|
|
107
|
+
*/
|
|
108
|
+
if (!shouldOpenDropdown) {
|
|
109
|
+
if (searchPosition === strings.SEARCH_POSITION_TRIGGER) {
|
|
110
|
+
if (isMultiple) {
|
|
111
|
+
this.focusInput();
|
|
112
|
+
} else {
|
|
113
|
+
this.toggle2SearchInput(true);
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
this._focusTrigger();
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
97
121
|
if (isMultiple) {
|
|
98
122
|
// when filter and multiple, focus input and open dropdown
|
|
99
123
|
this.focusInput();
|
|
@@ -1077,7 +1101,8 @@ export default class SelectFoundation extends BaseFoundation<SelectAdapter> {
|
|
|
1077
1101
|
this.clearInput(e);
|
|
1078
1102
|
}
|
|
1079
1103
|
// after click showClear button, the select need to be focused
|
|
1080
|
-
|
|
1104
|
+
// but don't open dropdown to avoid focus state confusion
|
|
1105
|
+
this.focus(undefined, false);
|
|
1081
1106
|
this.clearSelected();
|
|
1082
1107
|
// prevent this click open dropdown
|
|
1083
1108
|
e.stopPropagation();
|
package/switch/switch.scss
CHANGED
package/switch/variables.scss
CHANGED
|
@@ -30,7 +30,8 @@ $color-switch_disabled-border-default: var(--semi-color-border); // 禁用态开
|
|
|
30
30
|
$color-switch_disabled-bg-hover: transparent; // 禁用态开关背景色 - 悬浮
|
|
31
31
|
$color-switch_checked_disabled-bg-default: var(--semi-color-success-disabled); // 禁用开启态开关背景颜色
|
|
32
32
|
$color-switch_checked_disabled-border-default: transparent; // 禁用开启态开关描边颜色
|
|
33
|
-
$color-switch_knob-bg-default: rgba(var(--semi-white), 1); // 开关滑块背景颜色
|
|
33
|
+
$color-switch_knob-bg-default: rgba(var(--semi-white), 1); // 开关滑块背景颜色 - 关闭态
|
|
34
|
+
$color-switch_knob-bg-checked: rgba(var(--semi-white), 1); // 开关滑块背景颜色 - 开启态
|
|
34
35
|
$color-switch_knob-border-default: var(--semi-color-border); // 开关滑块描边颜色
|
|
35
36
|
$color-switch_checked-text-default: var(--semi-color-white); // 开启态开关文案颜色
|
|
36
37
|
$color-switch_unchecked-text-default: var(--semi-color-text-2); // 关闭态开关文案颜色
|