@douyinfe/semi-foundation 2.14.0 → 2.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/cascader/cascader.scss +20 -0
  2. package/cascader/foundation.ts +21 -0
  3. package/cascader/variables.scss +2 -0
  4. package/checkbox/checkbox.scss +9 -9
  5. package/checkbox/checkboxFoundation.ts +1 -0
  6. package/datePicker/foundation.ts +32 -8
  7. package/datePicker/monthsGridFoundation.ts +1 -2
  8. package/dropdown/dropdown.scss +4 -0
  9. package/dropdown/foundation.ts +38 -1
  10. package/dropdown/menuFoundation.ts +77 -0
  11. package/lib/cjs/cascader/cascader.css +15 -0
  12. package/lib/cjs/cascader/cascader.scss +20 -0
  13. package/lib/cjs/cascader/foundation.d.ts +6 -0
  14. package/lib/cjs/cascader/foundation.js +23 -0
  15. package/lib/cjs/cascader/variables.scss +2 -0
  16. package/lib/cjs/checkbox/checkbox.css +5 -5
  17. package/lib/cjs/checkbox/checkbox.scss +9 -9
  18. package/lib/cjs/checkbox/checkboxFoundation.d.ts +1 -0
  19. package/lib/cjs/datePicker/foundation.d.ts +7 -0
  20. package/lib/cjs/datePicker/foundation.js +38 -7
  21. package/lib/cjs/datePicker/monthsGridFoundation.js +1 -4
  22. package/lib/cjs/dropdown/dropdown.css +4 -0
  23. package/lib/cjs/dropdown/dropdown.scss +4 -0
  24. package/lib/cjs/dropdown/foundation.d.ts +4 -0
  25. package/lib/cjs/dropdown/foundation.js +48 -0
  26. package/lib/cjs/dropdown/menuFoundation.d.ts +9 -0
  27. package/lib/cjs/dropdown/menuFoundation.js +119 -0
  28. package/lib/cjs/list/list.css +1 -1
  29. package/lib/cjs/list/list.scss +1 -1
  30. package/lib/cjs/list/variables.scss +2 -1
  31. package/lib/cjs/modal/modalFoundation.d.ts +1 -0
  32. package/lib/cjs/rating/foundation.d.ts +13 -0
  33. package/lib/cjs/rating/foundation.js +123 -35
  34. package/lib/cjs/rating/rating.css +14 -5
  35. package/lib/cjs/rating/rating.scss +21 -8
  36. package/lib/cjs/rating/variables.scss +4 -0
  37. package/lib/cjs/tabs/foundation.js +28 -6
  38. package/lib/cjs/tooltip/foundation.js +39 -9
  39. package/lib/cjs/tree/foundation.d.ts +1 -0
  40. package/lib/cjs/treeSelect/foundation.js +9 -1
  41. package/lib/cjs/utils/FocusHandle.d.ts +1 -0
  42. package/lib/cjs/utils/FocusHandle.js +6 -1
  43. package/lib/cjs/utils/a11y.d.ts +9 -0
  44. package/lib/cjs/utils/a11y.js +123 -0
  45. package/lib/es/cascader/cascader.css +15 -0
  46. package/lib/es/cascader/cascader.scss +20 -0
  47. package/lib/es/cascader/foundation.d.ts +6 -0
  48. package/lib/es/cascader/foundation.js +23 -0
  49. package/lib/es/cascader/variables.scss +2 -0
  50. package/lib/es/checkbox/checkbox.css +5 -5
  51. package/lib/es/checkbox/checkbox.scss +9 -9
  52. package/lib/es/checkbox/checkboxFoundation.d.ts +1 -0
  53. package/lib/es/datePicker/foundation.d.ts +7 -0
  54. package/lib/es/datePicker/foundation.js +37 -7
  55. package/lib/es/datePicker/monthsGridFoundation.js +1 -3
  56. package/lib/es/dropdown/dropdown.css +4 -0
  57. package/lib/es/dropdown/dropdown.scss +4 -0
  58. package/lib/es/dropdown/foundation.d.ts +4 -0
  59. package/lib/es/dropdown/foundation.js +45 -0
  60. package/lib/es/dropdown/menuFoundation.d.ts +9 -0
  61. package/lib/es/dropdown/menuFoundation.js +99 -0
  62. package/lib/es/list/list.css +1 -1
  63. package/lib/es/list/list.scss +1 -1
  64. package/lib/es/list/variables.scss +2 -1
  65. package/lib/es/modal/modalFoundation.d.ts +1 -0
  66. package/lib/es/rating/foundation.d.ts +13 -0
  67. package/lib/es/rating/foundation.js +116 -32
  68. package/lib/es/rating/rating.css +14 -5
  69. package/lib/es/rating/rating.scss +21 -8
  70. package/lib/es/rating/variables.scss +4 -0
  71. package/lib/es/tabs/foundation.js +30 -6
  72. package/lib/es/tooltip/foundation.js +38 -9
  73. package/lib/es/tree/foundation.d.ts +1 -0
  74. package/lib/es/treeSelect/foundation.js +9 -1
  75. package/lib/es/utils/FocusHandle.d.ts +1 -0
  76. package/lib/es/utils/FocusHandle.js +6 -1
  77. package/lib/es/utils/a11y.d.ts +9 -0
  78. package/lib/es/utils/a11y.js +101 -0
  79. package/list/list.scss +1 -1
  80. package/list/variables.scss +2 -1
  81. package/modal/modalFoundation.ts +1 -0
  82. package/package.json +2 -2
  83. package/rating/foundation.ts +90 -31
  84. package/rating/rating.scss +21 -8
  85. package/rating/variables.scss +4 -0
  86. package/tabs/foundation.ts +9 -6
  87. package/tooltip/foundation.ts +16 -8
  88. package/tree/foundation.ts +1 -0
  89. package/treeSelect/foundation.ts +5 -1
  90. package/utils/FocusHandle.ts +3 -1
  91. package/utils/a11y.ts +105 -0
@@ -175,6 +175,17 @@ $module: #{$prefix}-cascader;
175
175
  height: $height-cascader_selection_tagInput_input_large;
176
176
  }
177
177
  }
178
+
179
+ &-text {
180
+
181
+ &-inactive {
182
+ color: $color-cascader_selection_text_inactive;
183
+ }
184
+
185
+ &-hide {
186
+ display: none;
187
+ }
188
+ }
178
189
  }
179
190
 
180
191
  &-arrow,
@@ -294,8 +305,17 @@ $module: #{$prefix}-cascader;
294
305
  .#{$module}-selection {
295
306
  .#{$module}-search-wrapper {
296
307
  width: 100%;
308
+ height: $height-cascader_selection_wrapper;
309
+ display: flex;
310
+ align-items: center;
311
+ position: relative;
297
312
 
298
313
  .#{$prefix}-input-wrapper {
314
+ position: absolute;
315
+ top: 0;
316
+ left: 0;
317
+ border: none;
318
+ background-color: transparent;
299
319
  height: 100%;
300
320
  width: 100%;
301
321
  border: $color-cascader_input-border-default;
@@ -145,6 +145,7 @@ export interface BasicCascaderProps {
145
145
  disableStrictly?: boolean;
146
146
  leafOnly?: boolean;
147
147
  enableLeafClick?: boolean;
148
+ preventScroll?: boolean;
148
149
  onClear?: () => void;
149
150
  triggerRender?: (props: BasicTriggerRenderProps) => any;
150
151
  onListScroll?: (e: any, panel: BasicScrollPanelProps) => void;
@@ -183,6 +184,7 @@ export interface BasicCascaderInnerData {
183
184
  isFocus?: boolean;
184
185
  isInput?: boolean;
185
186
  disabledKeys?: Set<string>;
187
+ showInput?: boolean;
186
188
  }
187
189
 
188
190
  export interface CascaderAdapter extends DefaultAdapter<BasicCascaderProps, BasicCascaderInnerData> {
@@ -208,6 +210,8 @@ export interface CascaderAdapter extends DefaultAdapter<BasicCascaderProps, Basi
208
210
  notifyOnLoad: (newLoadedKeys: Set<string>, data: BasicCascaderData) => void;
209
211
  notifyListScroll: (e: any, panel: BasicScrollPanelProps) => void;
210
212
  notifyOnExceed: (data: BasicEntity[]) => void;
213
+ toggleInputShow: (show: boolean, cb: () => void) => void;
214
+ updateFocusState: (focus: boolean) => void,
211
215
  }
212
216
 
213
217
  // eslint-disable-next-line max-len
@@ -484,9 +488,11 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
484
488
 
485
489
  open() {
486
490
  const filterable = this._isFilterable();
491
+ const { multiple } = this.getProps();
487
492
  this._adapter.openMenu();
488
493
  if (filterable) {
489
494
  this._clearInput();
495
+ !multiple && this.toggle2SearchInput(true);
490
496
  }
491
497
  if (this._isControlledComponent()) {
492
498
  this.reCalcActiveKeys();
@@ -524,10 +530,25 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
524
530
  inputValue = this.renderDisplayText([...selectedKeys][0]);
525
531
  }
526
532
  this._adapter.updateStates({ inputValue });
533
+ !multiple && this.toggle2SearchInput(false);
534
+ !multiple && this._adapter.updateFocusState(false);
527
535
  }
528
536
  this._notifyBlur(e);
529
537
  }
530
538
 
539
+ toggle2SearchInput(isShow: boolean) {
540
+ if (isShow) {
541
+ this._adapter.toggleInputShow(isShow, () => this.focusInput());
542
+ } else {
543
+ this._adapter.toggleInputShow(isShow, () => undefined);
544
+ }
545
+ }
546
+
547
+ focusInput() {
548
+ this._adapter.focusInput();
549
+ this._adapter.updateFocusState(true);
550
+ }
551
+
531
552
  getMergedMotion = () => {
532
553
  const { motion } = this.getProps();
533
554
  const { isSearching } = this.getStates();
@@ -54,6 +54,7 @@ $spacing-cascader_clearBtn-marginRight: 12px; // 级联选择触发器清空按
54
54
 
55
55
  $color-cascader_selection_n-text-default: var(--semi-color-text-0); // 超出 maxTagCount 后,+n 的文字默认颜色
56
56
  $color-cascader_selection_n-text-disabled: var(--semi-color-disabled-text); // 超出 maxTagCount 后,+n 的文字disabled颜色
57
+ $color-cascader_selection_text_inactive: var(--semi-color-text-2); // 级联选择单选inpu输入框和text并存时,text颜色
57
58
  $color-cascader_selection-text-default: var(--semi-color-text-0); // 级联选择选中项文字颜色
58
59
  $color-cascader_placeholder-text-default: var(--semi-color-text-2); // 级联选择未选中项文字颜色
59
60
  $color-cascader-icon-default: var(--semi-color-text-2); // 级联选择图标颜色 - 默认
@@ -94,6 +95,7 @@ $height-cascader_option_list: 180px; // 级联选择菜单高度
94
95
  $height-cascader_selection_tagInput_input_small: 22px;
95
96
  $height-cascader_selection_tagInput_input_default: 30px;
96
97
  $height-cascader_selection_tagInput_input_large: 38px;
98
+ $height-cascader_selection_wrapper: 30px;
97
99
 
98
100
  $spacing-cascader_text-marginX: $spacing-base-tight; // 级联选择 prefix/suffix 文字水平内间距
99
101
  $spacing-cascader_icon-marginX: $spacing-tight; // 级联选择 prefix/suffix 图标水平内间距
@@ -101,15 +101,6 @@ $module: #{$prefix}-checkbox;
101
101
  font-size: 16px;
102
102
  }
103
103
  }
104
-
105
- &-pureCardType {
106
- // Reasons to use opacity:0 & width: 0 instead of display: none
107
- // The a11y keyboard focus event of the checkbox depends on the implementation of the input focus/blur event
108
- // input focus/blur cannot take effect when display: none
109
- opacity: 0;
110
- width: 0;
111
- margin-right: 0 !important;
112
- }
113
104
  }
114
105
 
115
106
  &-inner-checked {
@@ -196,6 +187,15 @@ $module: #{$prefix}-checkbox;
196
187
  flex-shrink: 0;
197
188
  }
198
189
 
190
+ .#{$module}-inner-pureCardType {
191
+ // Reasons to use opacity:0 & width: 0 instead of display: none
192
+ // The a11y keyboard focus event of the checkbox depends on the implementation of the input focus/blur event
193
+ // input focus/blur cannot take effect when display: none
194
+ opacity: 0;
195
+ width: 0;
196
+ margin-right: 0;
197
+ }
198
+
199
199
  .#{$module}-addon {
200
200
  font-weight: $font-checkbox_cardType_addon-fontWeight;
201
201
  font-size: $font-checkbox_cardType_addon-size;
@@ -170,6 +170,7 @@ export interface BaseCheckboxProps {
170
170
  extra?: any;
171
171
  addonId?: string;
172
172
  extraId?: string;
173
+ preventScroll?: boolean;
173
174
  }
174
175
 
175
176
  export default CheckboxFoundation;
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-nested-ternary */
2
2
  /* eslint-disable max-len, max-depth, */
3
3
  import { format, isValid, isSameSecond, isEqual as isDateEqual, isDate } from 'date-fns';
4
- import { get, isObject, isString, isEqual } from 'lodash';
4
+ import { get, isObject, isString, isEqual, isFunction } from 'lodash';
5
5
 
6
6
  import BaseFoundation, { DefaultAdapter } from '../base/foundation';
7
7
  import { isValidDate, isTimestamp } from './_utils/index';
@@ -162,6 +162,7 @@ export interface DatePickerFoundationProps extends ElementProps, RenderProps, Ev
162
162
  localeCode?: string;
163
163
  rangeSeparator?: string;
164
164
  insetInput?: boolean;
165
+ preventScroll?: boolean;
165
166
  }
166
167
 
167
168
  export interface DatePickerFoundationState {
@@ -245,6 +246,23 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
245
246
  this._adapter.updateInputValue(null);
246
247
  this._adapter.updateValue(result);
247
248
  this.resetCachedSelectedValue(result);
249
+ this.initRangeInputFocus(result);
250
+
251
+ if (this._adapter.needConfirm()) {
252
+ this._adapter.updateCachedSelectedValue(result);
253
+ }
254
+ }
255
+
256
+ /**
257
+ * 如果用户传了一个空的 value,需要把 range input focus 设置为 rangeStart,这样用户可以清除完之后继续从开始选择
258
+ *
259
+ * If the user passes an empty value, you need to set the range input focus to rangeStart, so that the user can continue to select from the beginning after clearing
260
+ */
261
+ initRangeInputFocus(result: Date[]) {
262
+ const { triggerRender } = this.getProps();
263
+ if (this._isRangeType() && isFunction(triggerRender) && result.length === 0) {
264
+ this._adapter.setRangeInputFocus('rangeStart');
265
+ }
248
266
  }
249
267
 
250
268
  parseWithTimezone(value: ValueType, timeZone: string | number, prevTimeZone: string | number) {
@@ -1285,7 +1303,7 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
1285
1303
  * @returns
1286
1304
  */
1287
1305
  handleTriggerWrapperClick(e: any) {
1288
- const { disabled } = this._adapter.getProps();
1306
+ const { disabled, triggerRender } = this._adapter.getProps();
1289
1307
  const { rangeInputFocus } = this._adapter.getStates();
1290
1308
  if (disabled) {
1291
1309
  return;
@@ -1297,12 +1315,18 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
1297
1315
  * - When type is not range type, Input component will automatically focus in the same case
1298
1316
  * - isEventTarget is used to judge whether the event is a bubbling event
1299
1317
  */
1300
- if (this._isRangeType() && !rangeInputFocus && this._adapter.isEventTarget(e)) {
1301
- setTimeout(() => {
1302
- // using setTimeout get correct state value 'rangeInputFocus'
1303
- this.handleInputFocus(e, 'rangeStart');
1304
- this.openPanel();
1305
- }, 0);
1318
+ if (this._isRangeType() && !rangeInputFocus) {
1319
+ if (this._adapter.isEventTarget(e)) {
1320
+ setTimeout(() => {
1321
+ // using setTimeout get correct state value 'rangeInputFocus'
1322
+ this.handleInputFocus(e, 'rangeStart');
1323
+ }, 0);
1324
+ } else if (isFunction(triggerRender)) {
1325
+ // 如果是 triggerRender 场景,因为没有 input,因此打开面板时默认 focus 在 rangeStart
1326
+ // If it is a triggerRender scene, because there is no input, the default focus is rangeStart when the panel is opened
1327
+ this._adapter.setRangeInputFocus('rangeStart');
1328
+ }
1329
+ this.openPanel();
1306
1330
  } else {
1307
1331
  this.openPanel();
1308
1332
  }
@@ -724,9 +724,8 @@ export default class MonthsGridFoundation extends BaseFoundation<MonthsGridAdapt
724
724
  /**
725
725
  * no need to check focus then
726
726
  * - dateRange and isDateRangeAndHasOffset
727
- * - dateRange and triggerRender
728
727
  */
729
- const needCheckFocusRecord = !(type === 'dateRange' && (isDateRangeAndHasOffset || isFunction(triggerRender)));
728
+ const needCheckFocusRecord = !(type === 'dateRange' && isDateRangeAndHasOffset);
730
729
  this._adapter.notifySelectedChange(date, { needCheckFocusRecord });
731
730
  }
732
731
  }
@@ -50,6 +50,10 @@ $module: #{$prefix}-dropdown;
50
50
  &:not(.#{$module}-item-active):active {
51
51
  background-color: $color-dropdown_item-bg-active;
52
52
  }
53
+ &:focus-visible {
54
+ background-color: $color-dropdown_item-bg-hover;
55
+ outline: 0;
56
+ }
53
57
  &-icon {
54
58
  display: inline-flex;
55
59
  align-items: center;
@@ -1,5 +1,5 @@
1
1
  import BaseFoundation, { DefaultAdapter } from '../base/foundation';
2
-
2
+ import { handlePrevent, setFocusToFirstItem, setFocusToLastItem } from '../utils/a11y';
3
3
 
4
4
  export interface DropdownAdapter extends Partial<DefaultAdapter> {
5
5
  setPopVisible(visible: boolean): void;
@@ -11,4 +11,41 @@ export default class DropdownFoundation extends BaseFoundation<DropdownAdapter>
11
11
  this._adapter.setPopVisible(visible);
12
12
  this._adapter.notifyVisibleChange(visible);
13
13
  }
14
+
15
+ getMenuItemNodes(target: any): HTMLElement[] {
16
+ const id = target.attributes['data-popupid'].value;
17
+ const menuWrapper = document.getElementById(id);
18
+ // if has dropdown item, the item must wrapped by li
19
+ return menuWrapper ? Array.from(menuWrapper.getElementsByTagName('li')).filter(item => item.ariaDisabled === "false") : null;
20
+ }
21
+
22
+ setFocusToFirstMenuItem(target: any): void {
23
+ const menuItemNodes = this.getMenuItemNodes(target);
24
+ menuItemNodes && setFocusToFirstItem(menuItemNodes);
25
+ }
26
+
27
+ setFocusToLastMenuItem(target: any): void {
28
+ const menuItemNodes = this.getMenuItemNodes(target);
29
+ menuItemNodes && setFocusToLastItem(menuItemNodes);
30
+ }
31
+
32
+ handleKeyDown(event: any): void {
33
+ switch (event.key) {
34
+ case ' ':
35
+ case 'Enter':
36
+ event.target.click();
37
+ handlePrevent(event);
38
+ break;
39
+ case 'ArrowDown':
40
+ this.setFocusToFirstMenuItem(event.target);
41
+ handlePrevent(event);
42
+ break;
43
+ case 'ArrowUp':
44
+ this.setFocusToLastMenuItem(event.target);
45
+ handlePrevent(event);
46
+ break;
47
+ default:
48
+ break;
49
+ }
50
+ }
14
51
  }
@@ -0,0 +1,77 @@
1
+
2
+ import BaseFoundation, { DefaultAdapter } from '../base/foundation';
3
+ import { handlePrevent, isPrintableCharacter, findIndexByCharacter, getAncestorNodeByRole, getMenuButton, setFocusToFirstItem, setFocusToItem, setFocusToNextMenuitem, setFocusToPreviousMenuItem } from '../utils/a11y';
4
+
5
+
6
+ export default class DropdownMenuFoundation extends BaseFoundation<Partial<DefaultAdapter>> {
7
+ menuItemNodes: HTMLElement[] = null;
8
+ firstChars: string[] = [];
9
+
10
+ // if trigger is click, auto focus to the first menu item
11
+ autoFocus(ulElement: any): void {
12
+ const trigger = this._adapter.getContext('trigger');
13
+ if (trigger === 'click'){
14
+ // find all non-disabled li under this menu and set focus to the first menu
15
+ this.menuItemNodes = [...ulElement.getElementsByTagName('li')].filter(item => item.ariaDisabled !== "true");
16
+ setFocusToFirstItem(this.menuItemNodes);
17
+ }
18
+ }
19
+
20
+ handleEscape(menu: Element): void {
21
+ const trigger = this._adapter.getContext('trigger');
22
+ if (trigger === 'custom'){
23
+ const menuButton = menu && getMenuButton(document.querySelectorAll(`[data-popupid]`), menu.id);
24
+ menuButton.focus();
25
+ }
26
+ }
27
+
28
+ setFocusByFirstCharacter(curItem: any, char: string): void {
29
+ const index = findIndexByCharacter(this.menuItemNodes, curItem, this.firstChars, char);
30
+
31
+ if (index >= 0) {
32
+ setFocusToItem(this.menuItemNodes, this.menuItemNodes[index]);
33
+ }
34
+ }
35
+
36
+ onMenuKeydown(event: any): void {
37
+ const menu = getAncestorNodeByRole(event.target, 'tooltip');
38
+
39
+ if (!this.menuItemNodes){
40
+ this.menuItemNodes = [...(event.target.parentNode).getElementsByTagName('li')].filter(item => item.ariaDisabled !== "true");
41
+ }
42
+
43
+ if (this.firstChars.length === 0){
44
+ this.menuItemNodes.forEach((item: Element) => {
45
+ this.firstChars.push(item.textContent.trim()[0].toLowerCase());
46
+ });
47
+ }
48
+
49
+ // get the currently focused menu item
50
+ const curItem = this.menuItemNodes.find(item => item.tabIndex === 0);
51
+
52
+ switch (event.key) {
53
+ case ' ':
54
+ case 'Enter':
55
+ event.target.click();
56
+ handlePrevent(event);
57
+ break;
58
+ case 'Escape':
59
+ this.handleEscape(menu);
60
+ break;
61
+ case 'ArrowUp':
62
+ setFocusToPreviousMenuItem(this.menuItemNodes, curItem);
63
+ handlePrevent(event);
64
+ break;
65
+ case 'ArrowDown':
66
+ setFocusToNextMenuitem(this.menuItemNodes, curItem);
67
+ handlePrevent(event);
68
+ break;
69
+ default:
70
+ if (isPrintableCharacter(event.key)) {
71
+ this.setFocusByFirstCharacter(curItem, event.key);
72
+ handlePrevent(event);
73
+ }
74
+ break;
75
+ }
76
+ }
77
+ }
@@ -149,6 +149,12 @@
149
149
  .semi-cascader-selection .semi-tagInput .semi-input-wrapper-large {
150
150
  height: 38px;
151
151
  }
152
+ .semi-cascader-selection-text-inactive {
153
+ color: var(--semi-color-text-2);
154
+ }
155
+ .semi-cascader-selection-text-hide {
156
+ display: none;
157
+ }
152
158
  .semi-cascader-arrow, .semi-cascader-clearbtn {
153
159
  display: inline-flex;
154
160
  align-items: center;
@@ -242,8 +248,17 @@
242
248
  }
243
249
  .semi-cascader-single.semi-cascader-filterable .semi-cascader-selection .semi-cascader-search-wrapper {
244
250
  width: 100%;
251
+ height: 30px;
252
+ display: flex;
253
+ align-items: center;
254
+ position: relative;
245
255
  }
246
256
  .semi-cascader-single.semi-cascader-filterable .semi-cascader-selection .semi-cascader-search-wrapper .semi-input-wrapper {
257
+ position: absolute;
258
+ top: 0;
259
+ left: 0;
260
+ border: none;
261
+ background-color: transparent;
247
262
  height: 100%;
248
263
  width: 100%;
249
264
  border: none;
@@ -175,6 +175,17 @@ $module: #{$prefix}-cascader;
175
175
  height: $height-cascader_selection_tagInput_input_large;
176
176
  }
177
177
  }
178
+
179
+ &-text {
180
+
181
+ &-inactive {
182
+ color: $color-cascader_selection_text_inactive;
183
+ }
184
+
185
+ &-hide {
186
+ display: none;
187
+ }
188
+ }
178
189
  }
179
190
 
180
191
  &-arrow,
@@ -294,8 +305,17 @@ $module: #{$prefix}-cascader;
294
305
  .#{$module}-selection {
295
306
  .#{$module}-search-wrapper {
296
307
  width: 100%;
308
+ height: $height-cascader_selection_wrapper;
309
+ display: flex;
310
+ align-items: center;
311
+ position: relative;
297
312
 
298
313
  .#{$prefix}-input-wrapper {
314
+ position: absolute;
315
+ top: 0;
316
+ left: 0;
317
+ border: none;
318
+ background-color: transparent;
299
319
  height: 100%;
300
320
  width: 100%;
301
321
  border: $color-cascader_input-border-default;
@@ -99,6 +99,7 @@ export interface BasicCascaderProps {
99
99
  disableStrictly?: boolean;
100
100
  leafOnly?: boolean;
101
101
  enableLeafClick?: boolean;
102
+ preventScroll?: boolean;
102
103
  onClear?: () => void;
103
104
  triggerRender?: (props: BasicTriggerRenderProps) => any;
104
105
  onListScroll?: (e: any, panel: BasicScrollPanelProps) => void;
@@ -136,6 +137,7 @@ export interface BasicCascaderInnerData {
136
137
  isFocus?: boolean;
137
138
  isInput?: boolean;
138
139
  disabledKeys?: Set<string>;
140
+ showInput?: boolean;
139
141
  }
140
142
  export interface CascaderAdapter extends DefaultAdapter<BasicCascaderProps, BasicCascaderInnerData> {
141
143
  notifyClear?: () => void;
@@ -160,6 +162,8 @@ export interface CascaderAdapter extends DefaultAdapter<BasicCascaderProps, Basi
160
162
  notifyOnLoad: (newLoadedKeys: Set<string>, data: BasicCascaderData) => void;
161
163
  notifyListScroll: (e: any, panel: BasicScrollPanelProps) => void;
162
164
  notifyOnExceed: (data: BasicEntity[]) => void;
165
+ toggleInputShow: (show: boolean, cb: () => void) => void;
166
+ updateFocusState: (focus: boolean) => void;
163
167
  }
164
168
  export default class CascaderFoundation extends BaseFoundation<CascaderAdapter, BasicCascaderProps, BasicCascaderInnerData> {
165
169
  constructor(adapter: CascaderAdapter);
@@ -187,6 +191,8 @@ export default class CascaderFoundation extends BaseFoundation<CascaderAdapter,
187
191
  open(): void;
188
192
  reCalcActiveKeys(): void;
189
193
  close(e: any, key?: string): void;
194
+ toggle2SearchInput(isShow: boolean): void;
195
+ focusInput(): void;
190
196
  getMergedMotion: () => any;
191
197
  handleItemClick(e: any, item: BasicEntity | BasicData): void;
192
198
  handleItemHover(e: any, item: BasicEntity): void;
@@ -423,10 +423,16 @@ class CascaderFoundation extends _foundation.default {
423
423
  open() {
424
424
  const filterable = this._isFilterable();
425
425
 
426
+ const {
427
+ multiple
428
+ } = this.getProps();
429
+
426
430
  this._adapter.openMenu();
427
431
 
428
432
  if (filterable) {
429
433
  this._clearInput();
434
+
435
+ !multiple && this.toggle2SearchInput(true);
430
436
  }
431
437
 
432
438
  if (this._isControlledComponent()) {
@@ -486,11 +492,28 @@ class CascaderFoundation extends _foundation.default {
486
492
  this._adapter.updateStates({
487
493
  inputValue
488
494
  });
495
+
496
+ !multiple && this.toggle2SearchInput(false);
497
+ !multiple && this._adapter.updateFocusState(false);
489
498
  }
490
499
 
491
500
  this._notifyBlur(e);
492
501
  }
493
502
 
503
+ toggle2SearchInput(isShow) {
504
+ if (isShow) {
505
+ this._adapter.toggleInputShow(isShow, () => this.focusInput());
506
+ } else {
507
+ this._adapter.toggleInputShow(isShow, () => undefined);
508
+ }
509
+ }
510
+
511
+ focusInput() {
512
+ this._adapter.focusInput();
513
+
514
+ this._adapter.updateFocusState(true);
515
+ }
516
+
494
517
  handleItemClick(e, item) {
495
518
  const isDisabled = this._isDisabled();
496
519
 
@@ -54,6 +54,7 @@ $spacing-cascader_clearBtn-marginRight: 12px; // 级联选择触发器清空按
54
54
 
55
55
  $color-cascader_selection_n-text-default: var(--semi-color-text-0); // 超出 maxTagCount 后,+n 的文字默认颜色
56
56
  $color-cascader_selection_n-text-disabled: var(--semi-color-disabled-text); // 超出 maxTagCount 后,+n 的文字disabled颜色
57
+ $color-cascader_selection_text_inactive: var(--semi-color-text-2); // 级联选择单选inpu输入框和text并存时,text颜色
57
58
  $color-cascader_selection-text-default: var(--semi-color-text-0); // 级联选择选中项文字颜色
58
59
  $color-cascader_placeholder-text-default: var(--semi-color-text-2); // 级联选择未选中项文字颜色
59
60
  $color-cascader-icon-default: var(--semi-color-text-2); // 级联选择图标颜色 - 默认
@@ -94,6 +95,7 @@ $height-cascader_option_list: 180px; // 级联选择菜单高度
94
95
  $height-cascader_selection_tagInput_input_small: 22px;
95
96
  $height-cascader_selection_tagInput_input_default: 30px;
96
97
  $height-cascader_selection_tagInput_input_large: 38px;
98
+ $height-cascader_selection_wrapper: 30px;
97
99
 
98
100
  $spacing-cascader_text-marginX: $spacing-base-tight; // 级联选择 prefix/suffix 文字水平内间距
99
101
  $spacing-cascader_icon-marginX: $spacing-tight; // 级联选择 prefix/suffix 图标水平内间距
@@ -75,11 +75,6 @@
75
75
  .semi-checkbox-inner-display .semi-icon {
76
76
  font-size: 16px;
77
77
  }
78
- .semi-checkbox-inner-pureCardType {
79
- opacity: 0;
80
- width: 0;
81
- margin-right: 0 !important;
82
- }
83
78
  .semi-checkbox-inner-checked .semi-checkbox-inner-display {
84
79
  background: var(--semi-color-primary);
85
80
  color: var(--semi-color-white);
@@ -138,6 +133,11 @@
138
133
  .semi-checkbox-cardType .semi-checkbox-inner-display {
139
134
  background: var(--semi-color-white);
140
135
  }
136
+ .semi-checkbox-cardType .semi-checkbox-inner-pureCardType {
137
+ opacity: 0;
138
+ width: 0;
139
+ margin-right: 0;
140
+ }
141
141
  .semi-checkbox-cardType .semi-checkbox-addon {
142
142
  font-weight: 600;
143
143
  font-size: 14px;
@@ -101,15 +101,6 @@ $module: #{$prefix}-checkbox;
101
101
  font-size: 16px;
102
102
  }
103
103
  }
104
-
105
- &-pureCardType {
106
- // Reasons to use opacity:0 & width: 0 instead of display: none
107
- // The a11y keyboard focus event of the checkbox depends on the implementation of the input focus/blur event
108
- // input focus/blur cannot take effect when display: none
109
- opacity: 0;
110
- width: 0;
111
- margin-right: 0 !important;
112
- }
113
104
  }
114
105
 
115
106
  &-inner-checked {
@@ -196,6 +187,15 @@ $module: #{$prefix}-checkbox;
196
187
  flex-shrink: 0;
197
188
  }
198
189
 
190
+ .#{$module}-inner-pureCardType {
191
+ // Reasons to use opacity:0 & width: 0 instead of display: none
192
+ // The a11y keyboard focus event of the checkbox depends on the implementation of the input focus/blur event
193
+ // input focus/blur cannot take effect when display: none
194
+ opacity: 0;
195
+ width: 0;
196
+ margin-right: 0;
197
+ }
198
+
199
199
  .#{$module}-addon {
200
200
  font-weight: $font-checkbox_cardType_addon-fontWeight;
201
201
  font-size: $font-checkbox_cardType_addon-size;
@@ -62,5 +62,6 @@ export interface BaseCheckboxProps {
62
62
  extra?: any;
63
63
  addonId?: string;
64
64
  extraId?: string;
65
+ preventScroll?: boolean;
65
66
  }
66
67
  export default CheckboxFoundation;
@@ -131,6 +131,7 @@ export interface DatePickerFoundationProps extends ElementProps, RenderProps, Ev
131
131
  localeCode?: string;
132
132
  rangeSeparator?: string;
133
133
  insetInput?: boolean;
134
+ preventScroll?: boolean;
134
135
  }
135
136
  export interface DatePickerFoundationState {
136
137
  panelShow: boolean;
@@ -184,6 +185,12 @@ export default class DatePickerFoundation extends BaseFoundation<DatePickerAdapt
184
185
  initFromProps({ value, timeZone, prevTimeZone }: Pick<DatePickerFoundationProps, 'value' | 'timeZone'> & {
185
186
  prevTimeZone?: string | number;
186
187
  }): void;
188
+ /**
189
+ * 如果用户传了一个空的 value,需要把 range input focus 设置为 rangeStart,这样用户可以清除完之后继续从开始选择
190
+ *
191
+ * If the user passes an empty value, you need to set the range input focus to rangeStart, so that the user can continue to select from the beginning after clearing
192
+ */
193
+ initRangeInputFocus(result: Date[]): void;
187
194
  parseWithTimezone(value: ValueType, timeZone: string | number, prevTimeZone: string | number): Date[];
188
195
  _isMultiple(): boolean;
189
196
  /**