@rainbow-oh/yee-c 0.7.0 → 0.8.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 (127) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +40 -25
  3. package/dist/cjs/Card/card.js +7 -3
  4. package/dist/cjs/Carousel/carousel-item.js +7 -2
  5. package/dist/cjs/Carousel/carousel.js +31 -4
  6. package/dist/cjs/Cascader/cascader.js +1 -1
  7. package/dist/cjs/Cascader/column.js +1 -1
  8. package/dist/cjs/Cascader/node.js +16 -4
  9. package/dist/cjs/Cascader/search-list.js +13 -4
  10. package/dist/cjs/Checkbox/checkbox-group.js +1 -1
  11. package/dist/cjs/Checkbox/checkbox.js +6 -3
  12. package/dist/cjs/Collapse/panel.js +10 -1
  13. package/dist/cjs/Dialog/dialog.js +22 -7
  14. package/dist/cjs/Drawer/drawer.js +14 -5
  15. package/dist/cjs/Form/form-store.d.ts +2 -1
  16. package/dist/cjs/Form/form-store.js +32 -17
  17. package/dist/cjs/Menu/menu-item.js +14 -5
  18. package/dist/cjs/Menu/menu.js +10 -2
  19. package/dist/cjs/Pagination/items.js +10 -5
  20. package/dist/cjs/Pagination/pagination.js +9 -3
  21. package/dist/cjs/Radio/radio-group.js +6 -5
  22. package/dist/cjs/Radio/radio.js +39 -29
  23. package/dist/cjs/Rate/rate.js +6 -1
  24. package/dist/cjs/Rate/star.js +7 -3
  25. package/dist/cjs/Steps/step.js +7 -5
  26. package/dist/cjs/Steps/steps.js +1 -1
  27. package/dist/cjs/Table/hooks/useColumns.js +1 -1
  28. package/dist/cjs/Table/style/index.less +35 -11
  29. package/dist/cjs/Table/table.js +57 -7
  30. package/dist/cjs/Table/tbody/cell.js +1 -1
  31. package/dist/cjs/Table/util/header.d.ts +3 -1
  32. package/dist/cjs/Table/util/header.js +30 -3
  33. package/dist/cjs/Tabs/tab-content.js +3 -1
  34. package/dist/cjs/Tabs/tab-header/index.js +3 -1
  35. package/dist/cjs/Tabs/tab-header/tab-header-title.js +3 -1
  36. package/dist/cjs/hooks/useDelayState.js +3 -2
  37. package/dist/cjs/hooks/useFocusManage.d.ts +1 -1
  38. package/dist/cjs/hooks/useFocusManage.js +27 -22
  39. package/dist/cjs/style/color.css +2 -0
  40. package/dist/cjs/style/themes.css +1 -1
  41. package/dist/cjs/style/variables.css +3 -1
  42. package/dist/cjs/utils/focusStack.d.ts +6 -2
  43. package/dist/cjs/utils/focusStack.js +40 -11
  44. package/dist/cjs/version.d.ts +1 -1
  45. package/dist/cjs/version.js +1 -1
  46. package/dist/esm/Card/card.js +7 -3
  47. package/dist/esm/Carousel/carousel-item.js +7 -2
  48. package/dist/esm/Carousel/carousel.js +31 -4
  49. package/dist/esm/Cascader/cascader.js +3 -1
  50. package/dist/esm/Cascader/column.js +2 -1
  51. package/dist/esm/Cascader/node.js +18 -4
  52. package/dist/esm/Cascader/search-list.js +18 -4
  53. package/dist/esm/Checkbox/checkbox-group.js +3 -1
  54. package/dist/esm/Checkbox/checkbox.js +6 -3
  55. package/dist/esm/Collapse/panel.js +11 -2
  56. package/dist/esm/Dialog/dialog.js +26 -9
  57. package/dist/esm/Drawer/drawer.js +16 -7
  58. package/dist/esm/Form/form-store.d.ts +2 -1
  59. package/dist/esm/Form/form-store.js +40 -19
  60. package/dist/esm/Menu/menu-item.js +16 -5
  61. package/dist/esm/Menu/menu.js +11 -5
  62. package/dist/esm/Pagination/items.js +14 -5
  63. package/dist/esm/Pagination/pagination.js +16 -4
  64. package/dist/esm/Radio/radio-group.js +5 -4
  65. package/dist/esm/Radio/radio.js +5 -4
  66. package/dist/esm/Rate/rate.js +6 -1
  67. package/dist/esm/Rate/star.js +12 -4
  68. package/dist/esm/Steps/step.js +12 -6
  69. package/dist/esm/Steps/steps.js +3 -1
  70. package/dist/esm/Table/hooks/useColumns.js +1 -1
  71. package/dist/esm/Table/style/index.less +35 -11
  72. package/dist/esm/Table/table.js +54 -2
  73. package/dist/esm/Table/tbody/cell.js +1 -1
  74. package/dist/esm/Table/util/header.d.ts +3 -1
  75. package/dist/esm/Table/util/header.js +30 -2
  76. package/dist/esm/Tabs/tab-content.js +3 -1
  77. package/dist/esm/Tabs/tab-header/index.js +3 -1
  78. package/dist/esm/Tabs/tab-header/tab-header-title.js +3 -1
  79. package/dist/esm/hooks/useDelayState.js +5 -2
  80. package/dist/esm/hooks/useFocusManage.d.ts +1 -1
  81. package/dist/esm/hooks/useFocusManage.js +31 -13
  82. package/dist/esm/style/color.css +2 -0
  83. package/dist/esm/style/themes.css +1 -1
  84. package/dist/esm/style/variables.css +3 -1
  85. package/dist/esm/utils/focusStack.d.ts +6 -2
  86. package/dist/esm/utils/focusStack.js +37 -14
  87. package/dist/esm/version.d.ts +1 -1
  88. package/dist/esm/version.js +1 -1
  89. package/dist/umd/yee-c.min.css +3 -3
  90. package/dist/umd/yee-c.min.js +1 -1
  91. package/package.json +10 -6
  92. package/src/Card/card.tsx +5 -1
  93. package/src/Carousel/carousel-item.tsx +7 -1
  94. package/src/Carousel/carousel.tsx +30 -3
  95. package/src/Cascader/cascader.tsx +1 -1
  96. package/src/Cascader/column.tsx +1 -1
  97. package/src/Cascader/node.tsx +14 -2
  98. package/src/Cascader/search-list.tsx +11 -2
  99. package/src/Checkbox/checkbox-group.tsx +1 -1
  100. package/src/Checkbox/checkbox.tsx +3 -0
  101. package/src/Collapse/panel.tsx +11 -1
  102. package/src/Dialog/dialog.tsx +31 -6
  103. package/src/Drawer/drawer.tsx +12 -3
  104. package/src/Form/form-store.ts +42 -15
  105. package/src/Menu/menu-item.tsx +12 -3
  106. package/src/Menu/menu.tsx +11 -5
  107. package/src/Pagination/items.tsx +9 -4
  108. package/src/Pagination/pagination.tsx +10 -4
  109. package/src/Radio/radio-group.tsx +2 -1
  110. package/src/Radio/radio.tsx +7 -2
  111. package/src/Rate/rate.tsx +5 -0
  112. package/src/Rate/star.tsx +8 -4
  113. package/src/Steps/step.tsx +15 -5
  114. package/src/Steps/steps.tsx +1 -1
  115. package/src/Table/hooks/useColumns.ts +1 -1
  116. package/src/Table/style/index.less +35 -11
  117. package/src/Table/table.tsx +60 -1
  118. package/src/Table/tbody/cell.tsx +1 -1
  119. package/src/Table/util/header.ts +48 -2
  120. package/src/Tabs/tab-content.tsx +2 -0
  121. package/src/Tabs/tab-header/index.tsx +2 -0
  122. package/src/Tabs/tab-header/tab-header-title.tsx +3 -1
  123. package/src/hooks/useDelayState.ts +4 -2
  124. package/src/hooks/useFocusManage.ts +33 -17
  125. package/src/style/color.css +2 -0
  126. package/src/utils/focusStack.ts +55 -12
  127. package/src/version.ts +1 -1
package/src/Menu/menu.tsx CHANGED
@@ -40,9 +40,15 @@ const MenuGroup = ({
40
40
  prefixCls: string;
41
41
  renderItems: (items: MenuItemType[]) => React.ReactNode[];
42
42
  }) => (
43
- <li className={`${prefixCls}-item-group`}>
44
- <div className={`${prefixCls}-item-group-title`}>{item.label}</div>
45
- <ul className={`${prefixCls}-item-group-list`}>
43
+ <li className={`${prefixCls}-item-group`} role="none">
44
+ <div className={`${prefixCls}-item-group-title`} role="presentation" id={`${prefixCls}-group-${String(item.label)}`}>
45
+ {item.label}
46
+ </div>
47
+ <ul
48
+ className={`${prefixCls}-item-group-list`}
49
+ role="group"
50
+ aria-labelledby={`${prefixCls}-group-${String(item.label)}`}
51
+ >
46
52
  {renderItems(item.children)}
47
53
  </ul>
48
54
  </li>
@@ -112,11 +118,11 @@ const Menu = (props: InnerMenuProps) => {
112
118
  const rootStyle = root ? { ...style } : {};
113
119
 
114
120
  return (
115
- <ul {...dataAttrs} className={cls} style={rootStyle} role="menu">
121
+ <ul {...dataAttrs} className={cls} style={rootStyle} role={root && mode === 'horizontal' ? 'menubar' : 'menu'}>
116
122
  <MenuCtx.Provider value={{ level, mode, classNames, styles }}>
117
123
  {getChildFromItems(items)}
118
124
  {level === 0 && footer && (
119
- <li className={`${prefixCls}-footer`}>{footer}</li>
125
+ <li className={`${prefixCls}-footer`} role="none">{footer}</li>
120
126
  )}
121
127
  </MenuCtx.Provider>
122
128
  </ul>
@@ -81,18 +81,19 @@ const Items: React.FC<PaginationItemsProps> = (props) => {
81
81
  }
82
82
  }}
83
83
  role="button"
84
+ aria-label="Jump back 7 pages"
84
85
  key="turnleft"
85
86
  >
86
87
  {components?.jumpPrev ?? (
87
88
  <>
88
- <span className={`${prefixCls}-jump-prev-ellipsis`}>
89
+ <span className={`${prefixCls}-jump-prev-ellipsis`} aria-hidden="true">
89
90
  <Ellipsis
90
91
  className="ellipsis"
91
92
  size={18}
92
93
  strokeWidth={1.5}
93
94
  />
94
95
  </span>
95
- <span className={`${prefixCls}-jump-prev-icon`}>
96
+ <span className={`${prefixCls}-jump-prev-icon`} aria-hidden="true">
96
97
  <ChevronsLeft
97
98
  className="turn"
98
99
  size={18}
@@ -116,18 +117,19 @@ const Items: React.FC<PaginationItemsProps> = (props) => {
116
117
  }
117
118
  }}
118
119
  role="button"
120
+ aria-label="Jump forward 7 pages"
119
121
  key="turn-right"
120
122
  >
121
123
  {components?.jumpNext ?? (
122
124
  <>
123
- <span className={`${prefixCls}-jump-next-ellipsis`}>
125
+ <span className={`${prefixCls}-jump-next-ellipsis`} aria-hidden="true">
124
126
  <Ellipsis
125
127
  className="ellipsis"
126
128
  size={18}
127
129
  strokeWidth={1.5}
128
130
  />
129
131
  </span>
130
- <span className={`${prefixCls}-jump-next-icon`}>
132
+ <span className={`${prefixCls}-jump-next-icon`} aria-hidden="true">
131
133
  <ChevronsRight
132
134
  className="turn"
133
135
  size={18}
@@ -159,6 +161,9 @@ const Items: React.FC<PaginationItemsProps> = (props) => {
159
161
  onChange(number as number);
160
162
  }
161
163
  }}
164
+ role="button"
165
+ aria-label={`Page ${number}`}
166
+ aria-current={current === number ? 'page' : undefined}
162
167
  >
163
168
  {number}
164
169
  </li>
@@ -179,9 +179,12 @@ const Pagination = React.forwardRef(
179
179
  prevClick();
180
180
  }
181
181
  }}
182
+ role="button"
183
+ aria-label="Previous page"
184
+ aria-disabled={mergedCurrent === 1 || undefined}
182
185
  key="prev"
183
186
  >
184
- {components?.prev ?? <ChevronLeft size={20} strokeWidth={1.5} />}
187
+ {components?.prev ?? <ChevronLeft size={20} strokeWidth={1.5} aria-hidden="true" />}
185
188
  </li>
186
189
  );
187
190
  };
@@ -204,9 +207,12 @@ const Pagination = React.forwardRef(
204
207
  nextClick();
205
208
  }
206
209
  }}
210
+ role="button"
211
+ aria-label="Next page"
212
+ aria-disabled={mergedCurrent === pageCount || undefined}
207
213
  key="next"
208
214
  >
209
- {components?.next ?? <ChevronRight size={20} strokeWidth={1.5} />}
215
+ {components?.next ?? <ChevronRight size={20} strokeWidth={1.5} aria-hidden="true" />}
210
216
  </li>
211
217
  );
212
218
  };
@@ -249,13 +255,13 @@ const Pagination = React.forwardRef(
249
255
  }
250
256
 
251
257
  return (
252
- <ul {...rest} className={cls} style={style} ref={ref}>
258
+ <ul {...rest} className={cls} style={style} ref={ref} role="navigation" aria-label="Pagination" aria-disabled={disabled || undefined}>
253
259
  {renderTotal()}
254
260
  {renderPrevious()}
255
261
  {simple ? (
256
262
  <li className={`${prefixCls}-simple`}>
257
263
  {renderNumber(false)}
258
- <span className="split">/</span>
264
+ <span className="split" aria-hidden="true">/</span>
259
265
  <span className="total-page">{pageCount}</span>
260
266
  </li>
261
267
  ) : (
@@ -61,6 +61,8 @@ const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>(
61
61
  style={{ ...style, gap: gap }}
62
62
  ref={ref}
63
63
  role="radiogroup"
64
+ aria-disabled={disabled || undefined}
65
+ {...rest}
64
66
  >
65
67
  <GroupCtx.Provider
66
68
  value={{ name, buttonStyle, onChange: handleChange }}
@@ -68,7 +70,6 @@ const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>(
68
70
  {options?.map((option, index) => (
69
71
  <Radio
70
72
  disabled={disabled}
71
- {...rest}
72
73
  {...option}
73
74
  checked={option.value === mergedValue}
74
75
  key={option.value || index}
@@ -67,7 +67,12 @@ const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
67
67
  );
68
68
 
69
69
  return (
70
- <label className={cls} style={style} onClick={handleClick}>
70
+ <label
71
+ className={cls}
72
+ style={style}
73
+ onClick={handleClick}
74
+ aria-disabled={disabled || undefined}
75
+ >
71
76
  <span
72
77
  className={clsx(prefixCls, {
73
78
  [`${prefixCls}-disabled`]: disabled,
@@ -83,12 +88,12 @@ const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
83
88
  checked={mergedChecked}
84
89
  disabled={disabled}
85
90
  onChange={handleChange}
86
- aria-checked={mergedChecked}
87
91
  />
88
92
  {!buttonStyle && (
89
93
  <span
90
94
  className={clsx(`${prefixCls}-inner`, classNames?.inner)}
91
95
  style={styles?.inner}
96
+ aria-hidden="true"
92
97
  ></span>
93
98
  )}
94
99
  </span>
package/src/Rate/rate.tsx CHANGED
@@ -106,6 +106,11 @@ const Rate = React.forwardRef<HTMLUListElement, RateProps>((baseprops, ref) => {
106
106
  ref={componentRef}
107
107
  role="radiogroup"
108
108
  aria-label="Rating"
109
+ aria-disabled={disabled || undefined}
110
+ aria-valuemin={0}
111
+ aria-valuemax={count}
112
+ aria-valuenow={mergedValue}
113
+ aria-valuetext={`${mergedValue} out of ${count} stars`}
109
114
  >
110
115
  {Array(count)
111
116
  .fill(0)
package/src/Rate/star.tsx CHANGED
@@ -45,6 +45,7 @@ const Star: React.FC<StarProps> = (props) => {
45
45
  aria-checked={active}
46
46
  aria-posinset={index + 1}
47
47
  aria-setsize={count}
48
+ aria-label={`${index + 1} ${index + 1 === 1 ? 'star' : 'stars'}`}
48
49
  key={'star-' + index}
49
50
  >
50
51
  <div
@@ -57,6 +58,7 @@ const Star: React.FC<StarProps> = (props) => {
57
58
  }
58
59
  }}
59
60
  tabIndex={0}
61
+ aria-label={`${index + 0.5} stars`}
60
62
  key={'star-' + index + 'left'}
61
63
  >
62
64
  {character ? (
@@ -64,7 +66,7 @@ const Star: React.FC<StarProps> = (props) => {
64
66
  {renderCharacter()}
65
67
  </span>
66
68
  ) : (
67
- <StarHalf className={`${prefixCls}-star-half`} />
69
+ <StarHalf className={`${prefixCls}-star-half`} aria-hidden="true" />
68
70
  )}
69
71
  </div>
70
72
  <div
@@ -77,6 +79,7 @@ const Star: React.FC<StarProps> = (props) => {
77
79
  }
78
80
  }}
79
81
  tabIndex={0}
82
+ aria-label={`${index + 1} ${index + 1 === 1 ? 'star' : 'stars'}`}
80
83
  key={'star-' + index + 'right'}
81
84
  >
82
85
  {character ? (
@@ -84,7 +87,7 @@ const Star: React.FC<StarProps> = (props) => {
84
87
  {renderCharacter()}
85
88
  </span>
86
89
  ) : (
87
- <StarFull className={`${prefixCls}-star-full`} />
90
+ <StarFull className={`${prefixCls}-star-full`} aria-hidden="true" />
88
91
  )}
89
92
  </div>
90
93
  </li>
@@ -103,6 +106,7 @@ const Star: React.FC<StarProps> = (props) => {
103
106
  aria-checked={active}
104
107
  aria-posinset={index + 1}
105
108
  aria-setsize={count}
109
+ aria-label={`${index + 1} ${index + 1 === 1 ? 'star' : 'stars'}`}
106
110
  key={'star-' + index}
107
111
  >
108
112
  {character ? (
@@ -110,9 +114,9 @@ const Star: React.FC<StarProps> = (props) => {
110
114
  {renderCharacter()}
111
115
  </span>
112
116
  ) : active ? (
113
- <StarFull className={`${prefixCls}-star-active`} />
117
+ <StarFull className={`${prefixCls}-star-active`} aria-hidden="true" />
114
118
  ) : (
115
- <StarFull className={`${prefixCls}-star-inactive`} />
119
+ <StarFull className={`${prefixCls}-star-inactive`} aria-hidden="true" />
116
120
  )}
117
121
  </li>
118
122
  )}
@@ -43,6 +43,15 @@ const Step: React.FC<StepProps> = (props) => {
43
43
  status ??
44
44
  (index < current ? 'finish' : index === current ? 'process' : 'wait');
45
45
 
46
+ const statusLabel =
47
+ mergedStatus === 'finish'
48
+ ? 'completed'
49
+ : mergedStatus === 'process'
50
+ ? 'in progress'
51
+ : mergedStatus === 'error'
52
+ ? 'error'
53
+ : 'pending';
54
+
46
55
  const renderIcon = useMemo(() => {
47
56
  if (dot) return <span className={`${prefixCls}-item-dot`}></span>;
48
57
 
@@ -89,7 +98,7 @@ const Step: React.FC<StepProps> = (props) => {
89
98
  return (
90
99
  <>
91
100
  {type === 'ribbon' && (
92
- <div className={`${prefixCls}-item-ribbon-end ${ribbonStatus}`} />
101
+ <div className={`${prefixCls}-item-ribbon-end ${ribbonStatus}`} aria-hidden="true" />
93
102
  )}
94
103
  <div
95
104
  className={cls}
@@ -97,11 +106,12 @@ const Step: React.FC<StepProps> = (props) => {
97
106
  onClick={handleClick}
98
107
  onKeyDown={handleKeyDown}
99
108
  tabIndex={disabled ? -1 : onChange ? 0 : undefined}
100
- role={onChange ? 'button' : undefined}
109
+ role={onChange ? 'button' : 'listitem'}
101
110
  aria-disabled={disabled}
102
111
  aria-current={index === current ? 'step' : undefined}
112
+ aria-label={`Step ${index + 1}${typeof title === 'string' ? `: ${title}` : ''}, ${statusLabel}`}
103
113
  >
104
- <div className={`${prefixCls}-item-icon`}>{renderIcon}</div>
114
+ <div className={`${prefixCls}-item-icon`} aria-hidden="true">{renderIcon}</div>
105
115
  <div className={`${prefixCls}-item-content`}>
106
116
  <div className={`${prefixCls}-item-title`}>
107
117
  <span title={typeof title === 'string' ? title : undefined}>
@@ -117,12 +127,12 @@ const Step: React.FC<StepProps> = (props) => {
117
127
  </div>
118
128
  </div>
119
129
  {type === 'navigation' && (
120
- <div className={`${prefixCls}-item-navi-arrow`}>
130
+ <div className={`${prefixCls}-item-navi-arrow`} aria-hidden="true">
121
131
  <ChevronRight />
122
132
  </div>
123
133
  )}
124
134
  {type === 'ribbon' && (
125
- <div className={`${prefixCls}-item-ribbon-head ${ribbonStatus}`} />
135
+ <div className={`${prefixCls}-item-ribbon-head ${ribbonStatus}`} aria-hidden="true" />
126
136
  )}
127
137
  </>
128
138
  );
@@ -71,7 +71,7 @@ const Steps = forwardRef<HTMLDivElement, StepsProps>((baseprops, ref) => {
71
71
  };
72
72
 
73
73
  return (
74
- <div {...rest} className={cls} style={style} ref={ref}>
74
+ <div {...rest} className={cls} style={style} ref={ref} role="list" aria-label="Steps">
75
75
  <StepsContext.Provider value={contextValue}>
76
76
  {renderSteps()}
77
77
  </StepsContext.Provider>
@@ -58,7 +58,7 @@ export default function useColumns({
58
58
  const tree = injectSelectionExpand(base, rowSelection, expandable);
59
59
  const leaves = flattenLeafColumns(tree);
60
60
  const wraped = handleColumns(leaves);
61
- const rows = parseHeaderRows(tree);
61
+ const rows = parseHeaderRows(tree, wraped);
62
62
  return { wrapedColumns: wraped, headerRows: rows };
63
63
  }, [childColumns, columns, shouldRenderSelection, shouldRenderExpand]);
64
64
 
@@ -49,6 +49,12 @@
49
49
  background-color: var(--yee-table-head-cell-split-line-color, #eee);
50
50
  }
51
51
  }
52
+
53
+ &-fixed-left,
54
+ &-fixed-right {
55
+ position: sticky;
56
+ z-index: 1;
57
+ }
52
58
  }
53
59
 
54
60
  &-cell {
@@ -84,6 +90,16 @@
84
90
  &-wrapper {
85
91
  overflow: auto;
86
92
  width: 100%;
93
+
94
+ &-scroll-left @{pls}-cell-fixed-left-last {
95
+ box-shadow: 6px 0 6px -4px
96
+ var(--yee-table-fixed-left-after-bs-color);
97
+ }
98
+
99
+ &-scroll-right @{pls}-cell-fixed-right-first {
100
+ box-shadow: -6px 0 6px -4px
101
+ var(--yee-table-fixed-right-after-bs-color);
102
+ }
87
103
  }
88
104
 
89
105
  > table {
@@ -101,10 +117,18 @@
101
117
  }
102
118
  }
103
119
 
120
+ &-row {
121
+ background-color: var(--yee-table-row-bg-color);
122
+ }
123
+
104
124
  &-even-row {
105
125
  background-color: var(--yee-table-even-row-bg-color);
106
126
  }
107
127
 
128
+ &-odd-row {
129
+ background-color: var(--yee-table-odd-row-bg-color);
130
+ }
131
+
108
132
  &-column-sorters {
109
133
  display: inline-flex;
110
134
  align-items: center;
@@ -137,7 +161,7 @@
137
161
  &-fixed-left,
138
162
  &-fixed-right {
139
163
  position: sticky;
140
- background-color: inherit;
164
+ background-color: var(--yee-table-fixed-column-bg-color);
141
165
  }
142
166
  }
143
167
 
@@ -163,17 +187,17 @@
163
187
  }
164
188
  }
165
189
 
166
- &-odd-row {
167
- > @{pls}-cell {
168
- background-color: var(--yee-table-odd-row-bg-color);
169
- }
170
- }
190
+ // &-odd-row {
191
+ // > @{pls}-cell {
192
+ // background-color: var(--yee-table-odd-row-bg-color);
193
+ // }
194
+ // }
171
195
 
172
- &-even-row {
173
- > @{pls}-cell {
174
- background-color: var(--yee-table-even-row-bg-color);
175
- }
176
- }
196
+ // &-even-row {
197
+ // > @{pls}-cell {
198
+ // background-color: var(--yee-table-even-row-bg-color);
199
+ // }
200
+ // }
177
201
 
178
202
  &-footer {
179
203
  display: flex;
@@ -126,6 +126,36 @@ const Table = React.forwardRef<HTMLDivElement, TableProps>((baseprops, ref) => {
126
126
 
127
127
  // Track previous values to determine what action triggered onChange
128
128
  const prevSortersRef = useRef<typeof sorters>({});
129
+ const contentWrapperRef = useRef<HTMLDivElement>(null);
130
+ const contentRef = useRef<HTMLDivElement>(null);
131
+ const [horizontalScroll, setHorizontalScroll] = React.useState({
132
+ left: false,
133
+ right: false,
134
+ });
135
+
136
+ const updateHorizontalScroll = React.useCallback(() => {
137
+ const wrapper = contentWrapperRef.current;
138
+ const content = contentRef.current;
139
+ if (!wrapper || !content) return;
140
+
141
+ const scrollContainer =
142
+ content.scrollWidth - content.clientWidth > 1 ? content : wrapper;
143
+ const maxScrollLeft =
144
+ scrollContainer.scrollWidth - scrollContainer.clientWidth;
145
+ const hasHorizontalScroll = maxScrollLeft > 1;
146
+ const next = {
147
+ left: hasHorizontalScroll && scrollContainer.scrollLeft > 1,
148
+ right:
149
+ hasHorizontalScroll &&
150
+ scrollContainer.scrollLeft < maxScrollLeft - 1,
151
+ };
152
+
153
+ setHorizontalScroll((current) =>
154
+ current.left === next.left && current.right === next.right
155
+ ? current
156
+ : next,
157
+ );
158
+ }, []);
129
159
 
130
160
  // Wrap onFilter to trigger onChange
131
161
  const onFilter = React.useCallback(
@@ -173,6 +203,25 @@ const Table = React.forwardRef<HTMLDivElement, TableProps>((baseprops, ref) => {
173
203
  }
174
204
  }, [sorters, current, pageSize, pageData, sortedData, onChange]);
175
205
 
206
+ useEffect(() => {
207
+ updateHorizontalScroll();
208
+
209
+ const wrapper = contentWrapperRef.current;
210
+ const content = contentRef.current;
211
+ if (!wrapper || !content) return undefined;
212
+
213
+ if (typeof ResizeObserver === 'undefined') {
214
+ window.addEventListener('resize', updateHorizontalScroll);
215
+ return () => window.removeEventListener('resize', updateHorizontalScroll);
216
+ }
217
+
218
+ const resizeObserver = new ResizeObserver(updateHorizontalScroll);
219
+ resizeObserver.observe(wrapper);
220
+ resizeObserver.observe(content);
221
+
222
+ return () => resizeObserver.disconnect();
223
+ }, [updateHorizontalScroll, wrapedColumns, pageData, scroll?.x]);
224
+
176
225
  const renderHeader = () => {
177
226
  return (
178
227
  <Header
@@ -259,13 +308,23 @@ const Table = React.forwardRef<HTMLDivElement, TableProps>((baseprops, ref) => {
259
308
  );
260
309
 
261
310
  return (
262
- <div className={`${prefixCls}-content-wrapper`}>
311
+ <div
312
+ ref={contentWrapperRef}
313
+ className={clsx(`${prefixCls}-content-wrapper`, {
314
+ [`${prefixCls}-content-wrapper-scroll-left`]: horizontalScroll.left,
315
+ [`${prefixCls}-content-wrapper-scroll-right`]:
316
+ horizontalScroll.right,
317
+ })}
318
+ onScroll={updateHorizontalScroll}
319
+ >
263
320
  <div
321
+ ref={contentRef}
264
322
  className={clsx(`${prefixCls}-content`, {
265
323
  [`${prefixCls}-${size}-size`]: size,
266
324
  [`${prefixCls}-fixed-header`]: scroll?.y,
267
325
  })}
268
326
  style={{ height: scroll?.y, width: scroll?.x }}
327
+ onScroll={updateHorizontalScroll}
269
328
  >
270
329
  {table}
271
330
  </div>
@@ -61,7 +61,7 @@ const TableCell: React.FC<BodyCellProps> = (props) => {
61
61
  {
62
62
  [`${prefixCls}-cell-fixed-${fixed}`]: fixed,
63
63
  [`${prefixCls}-cell-fixed-${fixed}-first`]: isFixedRightFirst,
64
- [`${prefixCls}-fixed-${fixed}-last`]: isFixedLeftLast,
64
+ [`${prefixCls}-cell-fixed-${fixed}-last`]: isFixedLeftLast,
65
65
  },
66
66
  className,
67
67
  );
@@ -32,13 +32,17 @@ export function flattenLeafColumns(
32
32
  *
33
33
  * - Pass 1 (DFS): place each column into the row matching its depth; a group's
34
34
  * colSpan equals the sum of its children's colSpans.
35
+ * - Fixed metadata from the resolved leaf columns is reused by leaf cells and
36
+ * aggregated for group cells whose descendants share the same fixed side.
35
37
  * - Pass 2: leaf cells (no sub-columns) get rowSpan = rowCount - rowIndex so
36
38
  * they stretch down to the last header row; group cells keep rowSpan = 1.
37
39
  */
38
40
  export function parseHeaderRows(
39
41
  rootColumns: WrapedColumnProps[],
42
+ resolvedLeafColumns: WrapedColumnProps[] = flattenLeafColumns(rootColumns),
40
43
  ): HeaderCell[][] {
41
44
  const rows: HeaderCell[][] = [];
45
+ let leafIndex = 0;
42
46
 
43
47
  const fillRowCells = (
44
48
  columns: WrapedColumnProps[],
@@ -46,17 +50,59 @@ export function parseHeaderRows(
46
50
  ): number => {
47
51
  rows[rowIndex] = rows[rowIndex] || [];
48
52
  let colSpanTotal = 0;
49
- columns.filter(Boolean).forEach((column) => {
53
+ columns.filter(Boolean).forEach((sourceColumn) => {
54
+ let column = sourceColumn;
55
+ const subColumns = sourceColumn.children as
56
+ | WrapedColumnProps[]
57
+ | undefined;
58
+ const leafStartIndex = leafIndex;
50
59
  const cell: HeaderCell = {
51
60
  column,
52
61
  colSpan: 1,
53
62
  rowSpan: 1,
54
63
  };
55
- const subColumns = column.children as WrapedColumnProps[] | undefined;
64
+
56
65
  if (subColumns && subColumns.length > 0) {
57
66
  cell.colSpan = fillRowCells(subColumns, rowIndex + 1);
58
67
  cell.hasSubColumns = true;
68
+
69
+ const groupLeaves = resolvedLeafColumns.slice(
70
+ leafStartIndex,
71
+ leafIndex,
72
+ );
73
+ const fixed = groupLeaves[0]?.fixed;
74
+ const isFixedGroup =
75
+ (fixed === 'left' || fixed === 'right') &&
76
+ groupLeaves.every((leaf) => leaf.fixed === fixed);
77
+
78
+ if (isFixedGroup) {
79
+ const offsetLeaf =
80
+ fixed === 'left'
81
+ ? groupLeaves[0]
82
+ : groupLeaves[groupLeaves.length - 1];
83
+ const boundaryLeaf =
84
+ fixed === 'left'
85
+ ? groupLeaves[groupLeaves.length - 1]
86
+ : groupLeaves[0];
87
+ column = {
88
+ ...sourceColumn,
89
+ fixed,
90
+ style: {
91
+ ...sourceColumn.style,
92
+ [fixed]: offsetLeaf.style?.[fixed],
93
+ },
94
+ isFixedLeftLast: fixed === 'left' && boundaryLeaf.isFixedLeftLast,
95
+ isFixedRightFirst:
96
+ fixed === 'right' && boundaryLeaf.isFixedRightFirst,
97
+ };
98
+ cell.column = column;
99
+ }
100
+ } else {
101
+ column = resolvedLeafColumns[leafIndex] || sourceColumn;
102
+ cell.column = column;
103
+ leafIndex += 1;
59
104
  }
105
+
60
106
  rows[rowIndex].push(cell);
61
107
  colSpanTotal += cell.colSpan;
62
108
  });
@@ -67,9 +67,11 @@ const TabContent: React.FC<TabContentProps> = ({
67
67
  className={`${prefixCls}-tab-content`}
68
68
  style={{ display: activeKey === key ? 'block' : 'none' }}
69
69
  key={key}
70
+ id={`tabpanel-${key}`}
70
71
  role="tabpanel"
71
72
  aria-labelledby={`tab-${key}`}
72
73
  aria-hidden={activeKey !== key}
74
+ tabIndex={activeKey === key ? 0 : -1}
73
75
  >
74
76
  {children}
75
77
  </div>
@@ -170,6 +170,8 @@ const TabHeader: React.FC<TabHeaderProps> = (props) => {
170
170
  className={clsx(`${prefixCls}-nav-list`, classNames?.list)}
171
171
  style={styles?.list}
172
172
  ref={navList}
173
+ role="tablist"
174
+ aria-orientation={direction}
173
175
  >
174
176
  {items?.map((item: TabItemType, index: number) => (
175
177
  <TabHeaderTitle
@@ -166,10 +166,12 @@ const TabHeaderTitle: React.FC<TabsItemProps> = (props) => {
166
166
  {...rest}
167
167
  ref={tabRef}
168
168
  role="tab"
169
+ id={`tab-${$key}`}
169
170
  aria-selected={activeKey === $key}
170
171
  aria-disabled={disabled}
172
+ aria-controls={`tabpanel-${$key}`}
171
173
  className={cls}
172
- tabIndex={disabled ? -1 : 0}
174
+ tabIndex={disabled ? -1 : activeKey === $key ? 0 : -1}
173
175
  onClick={handleTabClick}
174
176
  onKeyDown={handleKeyDown}
175
177
  >
@@ -4,10 +4,12 @@ export default function useDelayState<T>(state: T, delay = 0): T {
4
4
  const [delayState, setDelayState] = useState<T>();
5
5
 
6
6
  useEffect(() => {
7
- setTimeout(() => {
7
+ const timer = window.setTimeout(() => {
8
8
  setDelayState(state);
9
9
  }, delay * 1000);
10
- }, [state]);
10
+
11
+ return () => window.clearTimeout(timer);
12
+ }, [delay, state]);
11
13
 
12
14
  return delayState as T;
13
15
  }