@douyinfe/semi-foundation 2.14.0-beta.2 → 2.15.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.
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
@@ -19,6 +19,10 @@ class TabsFoundation extends BaseFoundation {
19
19
  this.handleKeyDown = (event, itemKey, closable) => {
20
20
  var _context;
21
21
 
22
+ const {
23
+ preventScroll
24
+ } = this.getProps();
25
+
22
26
  const tabs = _filterInstanceProperty(_context = [...event.target.parentNode.childNodes]).call(_context, item => {
23
27
  var _context2;
24
28
 
@@ -45,13 +49,17 @@ class TabsFoundation extends BaseFoundation {
45
49
  break;
46
50
 
47
51
  case "Home":
48
- tabs[0].focus(); // focus first tab
52
+ tabs[0].focus({
53
+ preventScroll
54
+ }); // focus first tab
49
55
 
50
56
  this.handlePrevent(event);
51
57
  break;
52
58
 
53
59
  case "End":
54
- tabs[tabs.length - 1].focus(); // focus last tab
60
+ tabs[tabs.length - 1].focus({
61
+ preventScroll
62
+ }); // focus last tab
55
63
 
56
64
  this.handlePrevent(event);
57
65
  break;
@@ -146,6 +154,10 @@ class TabsFoundation extends BaseFoundation {
146
154
  }
147
155
 
148
156
  handleDeleteKeyDown(event, tabs, itemKey, closable) {
157
+ const {
158
+ preventScroll
159
+ } = this.getProps();
160
+
149
161
  if (closable) {
150
162
  this.handleTabDelete(itemKey);
151
163
 
@@ -154,12 +166,18 @@ class TabsFoundation extends BaseFoundation {
154
166
 
155
167
 
156
168
  if (tabs.length !== 1) {
157
- tabs[index + 1 >= tabs.length ? index - 1 : index + 1].focus();
169
+ tabs[index + 1 >= tabs.length ? index - 1 : index + 1].focus({
170
+ preventScroll
171
+ });
158
172
  }
159
173
  }
160
174
  }
161
175
 
162
176
  switchTabOnArrowPress(event, tabs) {
177
+ const {
178
+ preventScroll
179
+ } = this.getProps();
180
+
163
181
  const index = _indexOfInstanceProperty(tabs).call(tabs, event.target);
164
182
 
165
183
  const direction = {
@@ -172,11 +190,17 @@ class TabsFoundation extends BaseFoundation {
172
190
  if (direction[event.key]) {
173
191
  if (index !== undefined) {
174
192
  if (tabs[index + direction[event.key]]) {
175
- tabs[index + direction[event.key]].focus();
193
+ tabs[index + direction[event.key]].focus({
194
+ preventScroll
195
+ });
176
196
  } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
177
- tabs[tabs.length - 1].focus(); // focus last tab
197
+ tabs[tabs.length - 1].focus({
198
+ preventScroll
199
+ }); // focus last tab
178
200
  } else if (event.key === "ArrowRight" || event.key == "ArrowDown") {
179
- tabs[0].focus(); // focus first tab
201
+ tabs[0].focus({
202
+ preventScroll
203
+ }); // focus first tab
180
204
  }
181
205
  }
182
206
  }
@@ -7,6 +7,7 @@ import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/insta
7
7
  import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property";
8
8
  import _indexOfInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/index-of";
9
9
  import BaseFoundation from '../base/foundation';
10
+ import { handlePrevent } from '../utils/a11y';
10
11
  const REGS = {
11
12
  TOP: /top/i,
12
13
  RIGHT: /right/i,
@@ -936,6 +937,7 @@ export default class Tooltip extends BaseFoundation {
936
937
 
937
938
  switch (event && event.key) {
938
939
  case "Escape":
940
+ handlePrevent(event);
939
941
  closeOnEsc && this._handleEscKeyDown(event);
940
942
  break;
941
943
 
@@ -965,14 +967,17 @@ export default class Tooltip extends BaseFoundation {
965
967
  _focusTrigger() {
966
968
  const {
967
969
  trigger,
968
- returnFocusOnClose
970
+ returnFocusOnClose,
971
+ preventScroll
969
972
  } = this.getProps();
970
973
 
971
- if (returnFocusOnClose && trigger === 'click') {
974
+ if (returnFocusOnClose && trigger !== 'custom') {
972
975
  const triggerNode = this._adapter.getTriggerNode();
973
976
 
974
977
  if (triggerNode && 'focus' in triggerNode) {
975
- triggerNode.focus();
978
+ triggerNode.focus({
979
+ preventScroll
980
+ });
976
981
  }
977
982
  }
978
983
  }
@@ -983,43 +988,67 @@ export default class Tooltip extends BaseFoundation {
983
988
  } = this.getProps();
984
989
 
985
990
  if (trigger !== 'custom') {
986
- this.hide();
987
-
991
+ // Move the focus into the trigger first and then close the pop-up layer
992
+ // to avoid the problem of opening the pop-up layer again when the focus returns to the trigger in the case of hover and focus
988
993
  this._focusTrigger();
994
+
995
+ this.hide();
989
996
  }
990
997
 
991
998
  this._adapter.notifyEscKeydown(event);
992
999
  }
993
1000
 
994
1001
  _handleContainerTabKeyDown(focusableElements, event) {
1002
+ const {
1003
+ preventScroll
1004
+ } = this.getProps();
1005
+
995
1006
  const activeElement = this._adapter.getActiveElement();
996
1007
 
997
1008
  const isLastCurrentFocus = focusableElements[focusableElements.length - 1] === activeElement;
998
1009
 
999
1010
  if (isLastCurrentFocus) {
1000
- focusableElements[0].focus();
1011
+ focusableElements[0].focus({
1012
+ preventScroll
1013
+ });
1001
1014
  event.preventDefault(); // prevent browser default tab move behavior
1002
1015
  }
1003
1016
  }
1004
1017
 
1005
1018
  _handleContainerShiftTabKeyDown(focusableElements, event) {
1019
+ const {
1020
+ preventScroll
1021
+ } = this.getProps();
1022
+
1006
1023
  const activeElement = this._adapter.getActiveElement();
1007
1024
 
1008
1025
  const isFirstCurrentFocus = focusableElements[0] === activeElement;
1009
1026
 
1010
1027
  if (isFirstCurrentFocus) {
1011
- focusableElements[focusableElements.length - 1].focus();
1028
+ focusableElements[focusableElements.length - 1].focus({
1029
+ preventScroll
1030
+ });
1012
1031
  event.preventDefault(); // prevent browser default tab move behavior
1013
1032
  }
1014
1033
  }
1015
1034
 
1016
1035
  _handleTriggerArrowDownKeydown(focusableElements, event) {
1017
- focusableElements[0].focus();
1036
+ const {
1037
+ preventScroll
1038
+ } = this.getProps();
1039
+ focusableElements[0].focus({
1040
+ preventScroll
1041
+ });
1018
1042
  event.preventDefault(); // prevent browser default scroll behavior
1019
1043
  }
1020
1044
 
1021
1045
  _handleTriggerArrowUpKeydown(focusableElements, event) {
1022
- focusableElements[focusableElements.length - 1].focus();
1046
+ const {
1047
+ preventScroll
1048
+ } = this.getProps();
1049
+ focusableElements[focusableElements.length - 1].focus({
1050
+ preventScroll
1051
+ });
1023
1052
  event.preventDefault(); // prevent browser default scroll behavior
1024
1053
  }
1025
1054
 
@@ -168,6 +168,7 @@ export interface BasicTreeProps {
168
168
  onContextMenu?: (e: any, node: BasicTreeNodeData) => void;
169
169
  onSearch?: (sunInput: string) => void;
170
170
  onSelect?: (selectedKeys: string, selected: boolean, selectedNode: BasicTreeNodeData) => void;
171
+ preventScroll?: boolean;
171
172
  renderDraggingNode?: (nodeInstance: HTMLElement, node: BasicTreeNodeData) => HTMLElement;
172
173
  renderFullLabel?: (renderFullLabelProps: BasicRenderFullLabelProps) => any;
173
174
  renderLabel?: (label?: any, treeNode?: BasicTreeNodeData) => any;
@@ -318,8 +318,12 @@ export default class TreeSelectFoundation extends BaseFoundation {
318
318
  const isDisabled = this._isDisabled();
319
319
 
320
320
  const {
321
- isOpen
321
+ isOpen,
322
+ inputValue
322
323
  } = this.getStates();
324
+ const {
325
+ searchPosition
326
+ } = this.getProps();
323
327
 
324
328
  if (isDisabled) {
325
329
  return;
@@ -328,6 +332,10 @@ export default class TreeSelectFoundation extends BaseFoundation {
328
332
 
329
333
  this._notifyFocus(e);
330
334
  } else if (isOpen) {
335
+ if (searchPosition === 'trigger' && inputValue) {
336
+ return;
337
+ }
338
+
331
339
  this.close(e);
332
340
  }
333
341
  }
@@ -2,6 +2,7 @@ declare type FocusRedirectListener = (element: HTMLElement) => boolean;
2
2
  interface HandleOptions {
3
3
  enable?: boolean;
4
4
  onFocusRedirectListener?: FocusRedirectListener | FocusRedirectListener[];
5
+ preventScroll?: boolean;
5
6
  }
6
7
  declare class FocusTrapHandle {
7
8
  container: HTMLElement;
@@ -58,7 +58,12 @@ class FocusTrapHandle {
58
58
  };
59
59
 
60
60
  this.focusElement = (element, event) => {
61
- element === null || element === void 0 ? void 0 : element.focus();
61
+ const {
62
+ preventScroll
63
+ } = this.options;
64
+ element === null || element === void 0 ? void 0 : element.focus({
65
+ preventScroll
66
+ });
62
67
  event.preventDefault(); // prevent browser default tab move behavior
63
68
  };
64
69
 
@@ -1 +1,10 @@
1
1
  export declare function handlePrevent(event: any): void;
2
+ export declare function isPrintableCharacter(string: string): RegExpMatchArray;
3
+ export declare function setFocusToItem(itemNodes: HTMLElement[], targetItem: HTMLElement): void;
4
+ export declare function setFocusToFirstItem(itemNodes: HTMLElement[]): void;
5
+ export declare function setFocusToLastItem(itemNodes: HTMLElement[]): void;
6
+ export declare function setFocusToPreviousMenuItem(itemNodes: HTMLElement[], currentItem: HTMLElement): void;
7
+ export declare function setFocusToNextMenuitem(itemNodes: HTMLElement[], currentItem: HTMLElement): void;
8
+ export declare function findIndexByCharacter(itemList: HTMLElement[], curItem: HTMLElement, firstCharList: string[], char: string): number;
9
+ export declare function getAncestorNodeByRole(curElement: Element, role: string): Element;
10
+ export declare function getMenuButton(focusableEle: NodeListOf<HTMLElement>, Id: string): HTMLElement;
@@ -1,4 +1,105 @@
1
+ import _get from "lodash/get";
2
+ import _indexOfInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/index-of";
1
3
  export function handlePrevent(event) {
2
4
  event.stopPropagation();
3
5
  event.preventDefault();
6
+ }
7
+ export function isPrintableCharacter(string) {
8
+ return string.length === 1 && string.match(/\S/);
9
+ } // set focus to the target item in item list
10
+
11
+ export function setFocusToItem(itemNodes, targetItem) {
12
+ for (let i = 0; i < itemNodes.length; i++) {
13
+ if (itemNodes[i] === targetItem) {
14
+ itemNodes[i].tabIndex = 0;
15
+ itemNodes[i].focus();
16
+ } else {
17
+ itemNodes[i].tabIndex = -1;
18
+ }
19
+ }
20
+ } // set focus to the first item in item list
21
+
22
+ export function setFocusToFirstItem(itemNodes) {
23
+ itemNodes.length > 0 && setFocusToItem(itemNodes, itemNodes[0]);
24
+ } // set focus to the last item in item list
25
+
26
+ export function setFocusToLastItem(itemNodes) {
27
+ itemNodes.length > 0 && setFocusToItem(itemNodes, itemNodes[itemNodes.length - 1]);
28
+ } // set focus to the previous item in item list
29
+
30
+ export function setFocusToPreviousMenuItem(itemNodes, currentItem) {
31
+ let newMenuItem, index;
32
+
33
+ if (itemNodes.length > 0) {
34
+ if (currentItem === itemNodes[0]) {
35
+ newMenuItem = itemNodes[itemNodes.length - 1];
36
+ } else {
37
+ index = _indexOfInstanceProperty(itemNodes).call(itemNodes, currentItem);
38
+ newMenuItem = itemNodes[index - 1];
39
+ }
40
+
41
+ setFocusToItem(itemNodes, newMenuItem);
42
+ }
43
+ } // set focus to the next item in item list
44
+
45
+ export function setFocusToNextMenuitem(itemNodes, currentItem) {
46
+ let newMenuItem, index;
47
+
48
+ if (itemNodes.length > 0) {
49
+ if (currentItem === itemNodes[itemNodes.length - 1]) {
50
+ newMenuItem = itemNodes[0];
51
+ } else {
52
+ index = _indexOfInstanceProperty(itemNodes).call(itemNodes, currentItem);
53
+ newMenuItem = itemNodes[index + 1];
54
+ }
55
+
56
+ setFocusToItem(itemNodes, newMenuItem);
57
+ }
58
+ }
59
+ export function findIndexByCharacter(itemList, curItem, firstCharList, char) {
60
+ let start, index;
61
+
62
+ if (!itemList || !firstCharList || !char || char.length > 1) {
63
+ return -1;
64
+ }
65
+
66
+ char = char.toLowerCase(); // Get start index for search based on position of currentItem
67
+
68
+ start = _indexOfInstanceProperty(itemList).call(itemList, curItem) + 1;
69
+
70
+ if (start >= itemList.length) {
71
+ start = 0;
72
+ } // Check remaining menu items in the menu
73
+
74
+
75
+ index = _indexOfInstanceProperty(firstCharList).call(firstCharList, char, start); // If not found in remaining menu items, check from beginning
76
+
77
+ if (index === -1) {
78
+ index = _indexOfInstanceProperty(firstCharList).call(firstCharList, char, 0);
79
+ }
80
+
81
+ return index >= 0 ? index : -1;
82
+ }
83
+ export function getAncestorNodeByRole(curElement, role) {
84
+ if (!curElement) {
85
+ return null;
86
+ }
87
+
88
+ while (curElement.parentElement && _get(curElement.parentElement, 'attributes.role.value', '') !== role) {
89
+ curElement = curElement.parentElement;
90
+ }
91
+
92
+ return curElement.parentElement;
93
+ } // According to the Id, find the corresponding data-popupId element
94
+
95
+ export function getMenuButton(focusableEle, Id) {
96
+ for (let i = 0; i < focusableEle.length; i++) {
97
+ const curAriDescribedby = focusableEle[i].attributes['data-popupId'];
98
+
99
+ if (curAriDescribedby && curAriDescribedby.value === Id) {
100
+ return focusableEle[i];
101
+ }
102
+ }
103
+
104
+ return null;
4
105
  }
package/list/list.scss CHANGED
@@ -17,7 +17,7 @@ $module: #{$prefix}-list;
17
17
  }
18
18
 
19
19
  &-empty {
20
- padding: $spacing-list_empty-padding;
20
+ padding: $spacing-list_empty-paddingY $spacing-list_empty-paddingX;
21
21
  color: $color-list_empty-text-default;
22
22
  width: 100%;
23
23
  text-align: center;
@@ -1,7 +1,8 @@
1
1
  $color-list_default-border-default: var(--semi-color-border); // 列表描边颜色
2
2
  $color-list_empty-text-default: var(--semi-color-text-2); // 空状态下列表文字颜色
3
3
 
4
- $spacing-list_empty-padding: $spacing-base-tight; // 空状态列表内边距
4
+ $spacing-list_empty-paddingX: 0px; // 空状态列表水平内边距
5
+ $spacing-list_empty-paddingY: $spacing-base-tight; // 空状态列表垂直内边距
5
6
  $spacing-list_footer-paddingX: $spacing-base-tight; // 列表 footer 水平内边距
6
7
  $spacing-list_footer-paddingY: $spacing-loose; // 列表 footer 垂直内边距
7
8
  $spacing-list_item-paddingX: $spacing-base-tight; // 列表 item 水平内边距 - 默认尺寸
@@ -54,6 +54,7 @@ export interface ModalProps {
54
54
  keepDOM?: boolean;
55
55
  direction?: any;
56
56
  fullScreen?: boolean;
57
+ preventScroll?: boolean;
57
58
  }
58
59
 
59
60
  export interface ModalState {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@douyinfe/semi-foundation",
3
- "version": "2.14.0-beta.2",
3
+ "version": "2.15.0",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "build:lib": "node ./scripts/compileLib.js",
@@ -24,7 +24,7 @@
24
24
  "*.scss",
25
25
  "*.css"
26
26
  ],
27
- "gitHead": "b95b9eb9d6ded3aac3dc53afc48534d4e748a2e6",
27
+ "gitHead": "236be8e52864297171e3b08da20475139dadd633",
28
28
  "devDependencies": {
29
29
  "@babel/plugin-proposal-decorators": "^7.15.8",
30
30
  "@babel/plugin-transform-runtime": "^7.15.8",
@@ -1,10 +1,6 @@
1
1
  /* eslint-disable no-param-reassign */
2
2
  import BaseFoundation, { DefaultAdapter } from '../base/foundation';
3
-
4
- const KeyCode = {
5
- LEFT: 37,
6
- RIGHT: 39
7
- };
3
+ import warning from '../utils/warning';
8
4
 
9
5
  export interface RatingAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
10
6
  focus: () => void;
@@ -15,6 +11,7 @@ export interface RatingAdapter<P = Record<string, any>, S = Record<string, any>>
15
11
  notifyFocus: (e: any) => void;
16
12
  notifyBlur: (e: any) => void;
17
13
  notifyKeyDown: (e: any) => void;
14
+ setEmptyStarFocusVisible: (focusVisible: boolean) => void;
18
15
  }
19
16
 
20
17
  export default class RatingFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<RatingAdapter<P, S>, P, S> {
@@ -121,37 +118,99 @@ export default class RatingFoundation<P = Record<string, any>, S = Record<string
121
118
  }
122
119
 
123
120
  handleKeyDown(event: any, value: number) {
124
- const { keyCode } = event;
121
+ const { key } = event;
125
122
  const { count, allowHalf } = this.getProps();
126
123
  const direction = this._adapter.getContext('direction');
127
124
  const reverse = direction === 'rtl';
128
- if (keyCode === KeyCode.RIGHT && value < count && !reverse) {
129
- if (allowHalf) {
130
- value += 0.5;
131
- } else {
132
- value += 1;
133
- }
134
- } else if (keyCode === KeyCode.LEFT && value > 0 && !reverse) {
135
- if (allowHalf) {
136
- value -= 0.5;
137
- } else {
138
- value -= 1;
139
- }
140
- } else if (keyCode === KeyCode.RIGHT && value > 0 && reverse) {
141
- if (allowHalf) {
142
- value -= 0.5;
143
- } else {
144
- value -= 1;
125
+ const step = allowHalf ? 0.5 : 1;
126
+ let tempValue: number;
127
+ let newValue: number;
128
+ if (key === 'ArrowRight' || key === 'ArrowUp') {
129
+ tempValue = value + (reverse ? - step : step);
130
+ } else if (key === 'ArrowLeft' || key === 'ArrowDown') {
131
+ tempValue = value + (reverse ? step : - step);
132
+ }
133
+ if (tempValue > count) {
134
+ newValue = 0;
135
+ } else if (tempValue < 0) {
136
+ newValue = count;
137
+ } else {
138
+ newValue = tempValue;
139
+ }
140
+ if (['ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowDown'].includes(key)) {
141
+ this._adapter.notifyKeyDown(event);
142
+ this._adapter.updateValue(newValue);
143
+ this.changeFocusStar(newValue, event);
144
+ event.preventDefault();
145
+ this._adapter.notifyHoverChange(undefined, null);
146
+ }
147
+ }
148
+
149
+ changeFocusStar(value: number, event: any) {
150
+ const { count, allowHalf, preventScroll } = this.getProps();
151
+ const index = Math.ceil(value) - 1;
152
+ const starElement = [...event.currentTarget.childNodes].map(item => item.childNodes[0].childNodes);
153
+ if (index < 0) {
154
+ starElement[count][0].focus({ preventScroll });
155
+ } else {
156
+ starElement[index][allowHalf ? (value * 10 % 10 === 5 ? 0 : 1) : 0].focus({ preventScroll });
157
+ }
158
+ }
159
+
160
+ handleStarFocusVisible = (event: any) => {
161
+ const { target } = event;
162
+ const { count } = this.getProps();
163
+ // when rating 0 is focus visible
164
+ try {
165
+ if (target.matches(':focus-visible')) {
166
+ this._adapter.setEmptyStarFocusVisible(true);
145
167
  }
146
- } else if (keyCode === KeyCode.LEFT && value < count && reverse) {
147
- if (allowHalf) {
148
- value += 0.5;
149
- } else {
150
- value += 1;
168
+ } catch (error) {
169
+ warning(true, 'Warning: [Semi Rating] The current browser does not support the focus-visible');
170
+ }
171
+ }
172
+
173
+ handleStarBlur = (event: React.FocusEvent) => {
174
+ const { emptyStarFocusVisible } = this.getStates();
175
+ if (emptyStarFocusVisible) {
176
+ this._adapter.setEmptyStarFocusVisible(false);
177
+ }
178
+ }
179
+ }
180
+
181
+ export interface RatingItemAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
182
+ setFirstStarFocus: (value: boolean) => void;
183
+ setSecondStarFocus: (value: boolean) => void;
184
+ }
185
+
186
+ export class RatingItemFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<RatingItemAdapter<P, S>, P, S> {
187
+
188
+ constructor(adapter: RatingItemAdapter<P, S>) {
189
+ super({ ...RatingItemFoundation.defaultAdapter, ...adapter });
190
+ }
191
+
192
+ handleFocusVisible = (event: any, star: string) => {
193
+ const { target } = event;
194
+ // when rating 0 is focus visible
195
+ try {
196
+ if (target.matches(':focus-visible')) {
197
+ if (star === 'first') {
198
+ this._adapter.setFirstStarFocus(true);
199
+ } else {
200
+ this._adapter.setSecondStarFocus(true);
201
+ }
151
202
  }
203
+ } catch (error) {
204
+ warning(true, 'Warning: [Semi Rating] The current browser does not support the focus-visible');
205
+ }
206
+ }
207
+
208
+ handleBlur = (event: React.FocusEvent, star: string) => {
209
+ const { firstStarFocus, secondStarFocus } = this.getStates();
210
+ if (star === 'first') {
211
+ firstStarFocus && this._adapter.setFirstStarFocus(false);
212
+ } else {
213
+ secondStarFocus && this._adapter.setSecondStarFocus(false);
152
214
  }
153
- this._adapter.updateValue(value);
154
- event.preventDefault();
155
- this._adapter.notifyKeyDown(event);
156
215
  }
157
216
  }
@@ -1,4 +1,4 @@
1
- @import "./variables.scss";
1
+ @import './variables.scss';
2
2
 
3
3
  $module: #{$prefix}-rating;
4
4
 
@@ -7,10 +7,19 @@ $module: #{$prefix}-rating;
7
7
  margin: $spacing-rating-margin;
8
8
  padding: $spacing-rating-padding;
9
9
  color: $color-rating-icon-default;
10
- font-size: $font-rating-fontSize;
11
- line-height: unset;
10
+ // font-size: $font-rating-fontSize;
11
+ // line-height: unset;
12
12
  list-style: none;
13
13
  outline: none;
14
+ border-radius: 3px;
15
+
16
+ &-focus {
17
+ outline: $width-rating-outline-focus solid $color-rating-outline-focus;
18
+ }
19
+
20
+ &-no-focus {
21
+ outline: none;
22
+ }
14
23
 
15
24
  &-disabled &-star {
16
25
  cursor: default;
@@ -34,14 +43,14 @@ $module: #{$prefix}-rating;
34
43
  }
35
44
 
36
45
  & > div {
37
- &:focus {
38
- outline: 0;
39
- }
40
-
41
46
  &:hover,
42
47
  &:focus {
43
48
  transform: scale(1.1);
44
49
  }
50
+
51
+ &.#{$module}-star-disabled {
52
+ transform: none;
53
+ }
45
54
  }
46
55
 
47
56
  &-small {
@@ -58,6 +67,10 @@ $module: #{$prefix}-rating;
58
67
 
59
68
  &-wrapper {
60
69
  position: relative;
70
+ overflow: hidden;
71
+ border-radius: 3px;
72
+ width: 100%;
73
+ height: 100%;
61
74
  }
62
75
 
63
76
  &-first,
@@ -88,4 +101,4 @@ $module: #{$prefix}-rating;
88
101
  }
89
102
  }
90
103
 
91
- @import "./rtl.scss";
104
+ @import './rtl.scss';
@@ -1,6 +1,8 @@
1
1
  $color-rating-icon-default: rgba(var(--semi-yellow-5), 1); // 评分图标按钮颜色 - 已填
2
2
  $color-rating-bg-default: var(--semi-color-fill-0); // 评分图标按钮颜色 - 未填
3
3
 
4
+ $color-rating-outline-focus: var(--semi-color-primary-light-active); // 聚焦轮廓颜色
5
+
4
6
  $font-rating-fontSize: 20px; // 评分文本字体大小
5
7
 
6
8
  $spacing-rating-margin: 0px; // 整体外边距
@@ -12,3 +14,5 @@ $font-rating_item_small-fontSize: $width-rating_item_small; // 小尺寸评分
12
14
 
13
15
  $width-rating_item_default: 24px; // 评分项宽度
14
16
  $font-rating_item_default-fontSize: $width-rating_item_default; // 评分项文本字体大小
17
+
18
+ $width-rating-outline-focus: 2px; // 聚焦轮廓宽度