@rainbow-oh/yee-c 0.8.14 → 0.8.16

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 (69) hide show
  1. package/dist/cjs/Progress/circle.js +1 -1
  2. package/dist/cjs/Progress/line.js +1 -1
  3. package/dist/cjs/Progress/progress.js +2 -0
  4. package/dist/cjs/Progress/steps.js +1 -1
  5. package/dist/cjs/Search/search.js +45 -16
  6. package/dist/cjs/Select/interface.d.ts +2 -1
  7. package/dist/cjs/Spin/demo/types.js +1 -1
  8. package/dist/cjs/Spin/indicator.d.ts +1 -1
  9. package/dist/cjs/Spin/indicator.js +144 -0
  10. package/dist/cjs/Spin/interface.d.ts +1 -1
  11. package/dist/cjs/Spin/style/index.less +86 -0
  12. package/dist/cjs/Table/demo/fixed.d.ts +3 -0
  13. package/dist/cjs/Table/demo/fixed.js +123 -0
  14. package/dist/cjs/Table/hooks/useColumns.d.ts +2 -1
  15. package/dist/cjs/Table/hooks/useColumns.js +4 -3
  16. package/dist/cjs/Table/style/index.less +23 -3
  17. package/dist/cjs/Table/table.js +67 -21
  18. package/dist/cjs/Table/util/index.d.ts +1 -1
  19. package/dist/cjs/Table/util/index.js +16 -3
  20. package/dist/cjs/style/themes.css +1 -1
  21. package/dist/cjs/style/variables.css +1 -1
  22. package/dist/cjs/version.d.ts +1 -1
  23. package/dist/cjs/version.js +1 -1
  24. package/dist/esm/Progress/circle.js +2 -1
  25. package/dist/esm/Progress/line.js +2 -1
  26. package/dist/esm/Progress/progress.js +2 -0
  27. package/dist/esm/Progress/steps.js +6 -1
  28. package/dist/esm/Search/search.js +31 -7
  29. package/dist/esm/Select/interface.d.ts +2 -1
  30. package/dist/esm/Spin/demo/types.js +10 -7
  31. package/dist/esm/Spin/indicator.d.ts +1 -1
  32. package/dist/esm/Spin/indicator.js +137 -0
  33. package/dist/esm/Spin/interface.d.ts +1 -1
  34. package/dist/esm/Spin/style/index.less +86 -0
  35. package/dist/esm/Table/demo/fixed.d.ts +3 -0
  36. package/dist/esm/Table/demo/fixed.js +84 -0
  37. package/dist/esm/Table/hooks/useColumns.d.ts +2 -1
  38. package/dist/esm/Table/hooks/useColumns.js +4 -3
  39. package/dist/esm/Table/style/index.less +23 -3
  40. package/dist/esm/Table/table.js +85 -26
  41. package/dist/esm/Table/util/index.d.ts +1 -1
  42. package/dist/esm/Table/util/index.js +16 -3
  43. package/dist/esm/style/themes.css +1 -1
  44. package/dist/esm/style/variables.css +1 -1
  45. package/dist/esm/version.d.ts +1 -1
  46. package/dist/esm/version.js +1 -1
  47. package/dist/umd/yee-c.min.css +1 -1
  48. package/dist/umd/yee-c.min.js +1 -1
  49. package/package.json +1 -1
  50. package/src/Progress/circle.tsx +1 -1
  51. package/src/Progress/line.tsx +1 -1
  52. package/src/Progress/progress.tsx +2 -0
  53. package/src/Progress/steps.tsx +3 -1
  54. package/src/Search/search.tsx +33 -4
  55. package/src/Select/interface.ts +2 -1
  56. package/src/Spin/demo/types.tsx +18 -3
  57. package/src/Spin/index.en-US.md +5 -2
  58. package/src/Spin/index.zh-CN.md +5 -2
  59. package/src/Spin/indicator.tsx +165 -1
  60. package/src/Spin/interface.ts +1 -1
  61. package/src/Spin/style/index.less +86 -0
  62. package/src/Table/demo/fixed.tsx +92 -0
  63. package/src/Table/hooks/useColumns.ts +4 -2
  64. package/src/Table/index.en-US.md +1 -0
  65. package/src/Table/index.zh-CN.md +1 -0
  66. package/src/Table/style/index.less +23 -3
  67. package/src/Table/table.tsx +88 -23
  68. package/src/Table/util/index.ts +32 -7
  69. package/src/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-oh/yee-c",
3
- "version": "0.8.14",
3
+ "version": "0.8.16",
4
4
  "description": "yee basic components",
5
5
  "keywords": [
6
6
  "react",
@@ -111,7 +111,7 @@ const Circle = React.forwardRef<HTMLDivElement, CircleProps>((props, ref) => {
111
111
  style={{ width, height: width }}
112
112
  ref={ref}
113
113
  >
114
- <svg className={`${prefixCls}-circle`} viewBox="0 0 120 120">
114
+ <svg className={`${prefixCls}-circle`} viewBox="0 0 120 120" aria-hidden="true">
115
115
  <circle
116
116
  className={`${prefixCls}-circle-trail`}
117
117
  cx="60"
@@ -36,7 +36,7 @@ const Line = React.forwardRef<HTMLDivElement, LineProps>((props, ref) => {
36
36
 
37
37
  return (
38
38
  <div className={`${prefixCls}-outer`} ref={ref}>
39
- <div className={`${prefixCls}-inner`} style={{ height: strokeWidth }}>
39
+ <div className={`${prefixCls}-inner`} style={{ height: strokeWidth }} aria-hidden="true">
40
40
  <div
41
41
  className={`${prefixCls}-bg`}
42
42
  style={{ width: percent + '%', ...progressColor }}
@@ -106,6 +106,8 @@ const Progress = React.forwardRef<HTMLDivElement, ProgressProps>(
106
106
  aria-valuenow={percent}
107
107
  aria-valuemin={0}
108
108
  aria-valuemax={100}
109
+ aria-valuetext={`${percent}%`}
110
+ aria-label={status === 'error' ? `Progress: ${percent}%, error` : `Progress: ${percent}%`}
109
111
  ref={ref}
110
112
  {...dataAttrs}
111
113
  >
@@ -56,7 +56,9 @@ const Steps = React.forwardRef<HTMLDivElement, StepsProps>((props, ref) => {
56
56
 
57
57
  return (
58
58
  <div className={`${prefixCls}-steps`} ref={ref}>
59
- {renderSteps()}
59
+ <div aria-hidden="true" style={{ display: 'contents' }}>
60
+ {renderSteps()}
61
+ </div>
60
62
  {showInfo && <span className={`${prefixCls}-text`}>{children}</span>}
61
63
  </div>
62
64
  );
@@ -4,6 +4,7 @@ import React, {
4
4
  startTransition,
5
5
  useContext,
6
6
  useEffect,
7
+ useId,
7
8
  useRef,
8
9
  useState,
9
10
  } from 'react';
@@ -55,6 +56,7 @@ const Search = React.forwardRef<HTMLInputElement, SearchProps>(
55
56
  const [open, setOpen] = useState(false);
56
57
 
57
58
  const popupRef = useRef<HTMLDivElement>(undefined);
59
+ const listboxId = useId();
58
60
 
59
61
  const { focusedKey, onKeyDown } = useSelectKeyboard({
60
62
  open,
@@ -130,8 +132,17 @@ const Search = React.forwardRef<HTMLInputElement, SearchProps>(
130
132
  className={clsx(`${prefixCls}-clear-icon`, classNames?.clear)}
131
133
  style={styles?.clear}
132
134
  onClick={handleClear}
135
+ role="button"
136
+ aria-label="Clear search"
137
+ tabIndex={0}
138
+ onKeyDown={(e) => {
139
+ if (e.key === 'Enter' || e.key === ' ') {
140
+ e.preventDefault();
141
+ handleClear(e as unknown as React.MouseEvent<HTMLSpanElement>);
142
+ }
143
+ }}
133
144
  >
134
- <X size={14} />
145
+ <X size={14} aria-hidden="true" />
135
146
  </span>
136
147
  )}
137
148
  {suffix}
@@ -174,8 +185,10 @@ const Search = React.forwardRef<HTMLInputElement, SearchProps>(
174
185
  );
175
186
  };
176
187
 
188
+ const hasPopup = Array.isArray(options) || Array.isArray(suggestions);
189
+
177
190
  const popup = (
178
- <div className={`${prefixCls}-popup`} tabIndex={0}>
191
+ <div className={`${prefixCls}-popup`} tabIndex={0} id={listboxId} role="listbox">
179
192
  {Array.isArray(options) ? (
180
193
  <List
181
194
  focusedKey={focusedKey}
@@ -196,7 +209,15 @@ const Search = React.forwardRef<HTMLInputElement, SearchProps>(
196
209
 
197
210
  return (
198
211
  <Trigger popup={popup} open={open} onOpenChange={setOpen}>
199
- <div className={getRootClassName()} style={style}>
212
+ <div
213
+ className={getRootClassName()}
214
+ style={style}
215
+ role="combobox"
216
+ aria-expanded={hasPopup ? open : undefined}
217
+ aria-haspopup={hasPopup ? 'listbox' : undefined}
218
+ aria-owns={hasPopup && open ? listboxId : undefined}
219
+ aria-disabled={disabled || undefined}
220
+ >
200
221
  {renderPrefix()}
201
222
  <input
202
223
  {...rest}
@@ -208,8 +229,16 @@ const Search = React.forwardRef<HTMLInputElement, SearchProps>(
208
229
  placeholder={placeholder}
209
230
  onChange={handleChange}
210
231
  onKeyDown={onKeyDown}
232
+ role="searchbox"
233
+ aria-autocomplete={hasPopup ? 'list' : undefined}
234
+ aria-controls={hasPopup && open ? listboxId : undefined}
235
+ aria-activedescendant={
236
+ hasPopup && open && focusedKey !== null
237
+ ? String(focusedKey)
238
+ : undefined
239
+ }
211
240
  />
212
- {loading ? <Spin variant="ring" size="small" /> : renderSuffix()}
241
+ {loading ? <Spin variant="ring" size="small" aria-label="Loading" /> : renderSuffix()}
213
242
  </div>
214
243
  </Trigger>
215
244
  );
@@ -1,3 +1,4 @@
1
+ import type { TriggerProps } from '../Trigger';
1
2
  import type { SelectorProps } from '../Selector';
2
3
  import type { DataAttributeProps } from '../utils/types';
3
4
 
@@ -25,7 +26,7 @@ export type Option = {
25
26
  };
26
27
 
27
28
  export interface SelectProps
28
- extends DataAttributeProps, Pick<SelectorProps, 'size'> {
29
+ extends DataAttributeProps, Pick<SelectorProps, 'size'>, Omit<TriggerProps, 'popup' | 'children'> {
29
30
  /**
30
31
  * Custom class name prefix
31
32
  * */
@@ -5,19 +5,34 @@ export default () => {
5
5
  return (
6
6
  <Space direction="vertical">
7
7
  <Space>
8
- <Spin variant="dot" color="error"/>
8
+ <Spin variant="dot" />
9
9
  <span>dot</span>
10
10
  </Space>
11
11
 
12
12
  <Space>
13
- <Spin variant="ring" color="error"/>
13
+ <Spin variant="ring" />
14
14
  <span>ring</span>
15
15
  </Space>
16
16
 
17
17
  <Space>
18
- <Spin variant="spokes" color="error"/>
18
+ <Spin variant="spokes" />
19
19
  <span>spokes</span>
20
20
  </Space>
21
+
22
+ <Space>
23
+ <Spin variant="bounce" />
24
+ <span>bounce</span>
25
+ </Space>
26
+
27
+ <Space>
28
+ <Spin variant="pulse" />
29
+ <span>pulse</span>
30
+ </Space>
31
+
32
+ <Space>
33
+ <Spin variant="wheel" />
34
+ <span>wheel</span>
35
+ </Space>
21
36
  </Space>
22
37
  );
23
38
  };
@@ -43,7 +43,7 @@ Used for page and block loading status.
43
43
  | styles | `Partial<Record<'tip' \| 'indicator', React.CSSProperties>>` | Semantic structure styles | - |
44
44
  | tip | `React.ReactNode` | Loading tip text | - |
45
45
  | delay | `number` | Delay in milliseconds to show loading effect | - |
46
- | variant | `'dot' \| 'ring' \| 'spokes'` | Indicator variant, `ring` for rotating circle, `spokes` for radiating lines | `'dot'` |
46
+ | variant | `'dot' \| 'ring' \| 'spokes' \| 'bounce' \| 'pulse' \| 'wheel'` | Indicator variant, `ring` for rotating circle, `spokes` for radiating lines, `bounce` for bouncing dots, `pulse` for pulsing circles, `wheel` for spokes with hollow center | `'dot'` |
47
47
  | indicator | `React.ReactNode` | Loading indicator | - |
48
48
  | mask | `boolean` | Whether to show mask | - |
49
49
  | children | `React.ReactNode` | Children elements | - |
@@ -54,4 +54,7 @@ Used for page and block loading status.
54
54
  | --- | --- |
55
55
  | dot | dot circle |
56
56
  | ring | rotating circle |
57
- | spokes | Spokes type |
57
+ | spokes | Spokes type |
58
+ | bounce | Bouncing dots |
59
+ | pulse | Pulsing circles |
60
+ | wheel | Spokes with hollow center |
@@ -43,7 +43,7 @@ toc: 'content'
43
43
  | styles | `Partial<Record<'tip' \| 'indicator', React.CSSProperties>>` | 语义化结构样式 | - |
44
44
  | tip | `React.ReactNode` | 加载状态的提示词 | - |
45
45
  | delay | `number` | 延迟显示加载效果的时间(毫秒) | - |
46
- | variant | `'dot' \| 'ring' \| 'spokes'` | 加载器样式变体,`ring` 为圆环转圈,`spokes` 为辐条旋转 | `'dot'` |
46
+ | variant | `'dot' \| 'ring' \| 'spokes' \| 'bounce' \| 'pulse' \| 'wheel'` | 加载器样式变体,`ring` 为圆环转圈,`spokes` 为辐条旋转,`bounce` 为弹跳圆点,`pulse` 为脉冲圆圈,`wheel` 为带中心空圆的辐条 | `'dot'` |
47
47
  | indicator | `React.ReactNode` | 加载器指示符 | - |
48
48
  | mask | `boolean` | 是否显示遮罩 | - |
49
49
  | children | `React.ReactNode` | 子元素 | - |
@@ -54,4 +54,7 @@ toc: 'content'
54
54
  | --- | --- |
55
55
  | dot | 原点旋转 |
56
56
  | ring | 圆环转圈 |
57
- | spokes | 辐条类型 |
57
+ | spokes | 辐条类型 |
58
+ | bounce | 弹跳圆点 |
59
+ | pulse | 脉冲圆圈 |
60
+ | wheel | 中空辐条(辐条离中心有距离,中间形成空圆) |
@@ -188,8 +188,163 @@ const DotSpinner: React.FC<SpinProps> = (props) => {
188
188
  );
189
189
  };
190
190
 
191
+ /**
192
+ * Bounce spinner - three dots that bounce up and down sequentially
193
+ */
194
+ const BounceSpinner: React.FC<SpinProps> = (props) => {
195
+ const {
196
+ prefixCls = 'yee-spin',
197
+ size = 'default',
198
+ classNames,
199
+ styles,
200
+ width,
201
+ height,
202
+ color,
203
+ } = props;
204
+
205
+ const containerSize = sizeMap[size];
206
+ const dotSizeMap = { small: 4, default: 6, large: 10 };
207
+ const dotSize = dotSizeMap[size];
208
+
209
+ return (
210
+ <div
211
+ className={clsx(
212
+ `${prefixCls}-indicator`,
213
+ `${prefixCls}-indicator-bounce`,
214
+ classNames?.indicator,
215
+ )}
216
+ style={{
217
+ width: width || containerSize,
218
+ height: height || containerSize,
219
+ ...styles?.indicator,
220
+ }}
221
+ >
222
+ <div className={`${prefixCls}-bounce`}>
223
+ {[0, 1, 2].map((i) => (
224
+ <span
225
+ key={i}
226
+ className={`${prefixCls}-bounce-dot`}
227
+ style={{
228
+ width: dotSize,
229
+ height: dotSize,
230
+ animationDelay: `${i * 0.15}s`,
231
+ backgroundColor: color,
232
+ }}
233
+ />
234
+ ))}
235
+ </div>
236
+ </div>
237
+ );
238
+ };
239
+
240
+ /**
241
+ * Pulse spinner - a circle that pulses (scales up and fades out) repeatedly
242
+ */
243
+ const PulseSpinner: React.FC<SpinProps> = (props) => {
244
+ const {
245
+ prefixCls = 'yee-spin',
246
+ size = 'default',
247
+ classNames,
248
+ styles,
249
+ width,
250
+ height,
251
+ color,
252
+ } = props;
253
+
254
+ const containerSize = sizeMap[size];
255
+
256
+ return (
257
+ <div
258
+ className={clsx(
259
+ `${prefixCls}-indicator`,
260
+ `${prefixCls}-indicator-pulse`,
261
+ classNames?.indicator,
262
+ )}
263
+ style={{
264
+ width: width || containerSize,
265
+ height: height || containerSize,
266
+ ...styles?.indicator,
267
+ }}
268
+ >
269
+ <span
270
+ className={`${prefixCls}-pulse-circle`}
271
+ style={{ backgroundColor: color }}
272
+ />
273
+ <span
274
+ className={`${prefixCls}-pulse-circle ${prefixCls}-pulse-circle-delay`}
275
+ style={{ backgroundColor: color }}
276
+ />
277
+ </div>
278
+ );
279
+ };
280
+
281
+ /**
282
+ * Wheel spinner - similar to spokes but each line is offset from center,
283
+ * creating a visible hollow circle in the middle
284
+ */
285
+ const WheelSpinner: React.FC<SpinProps> = (props) => {
286
+ const {
287
+ prefixCls = 'yee-spin',
288
+ size = 'default',
289
+ classNames,
290
+ styles,
291
+ width,
292
+ height,
293
+ color,
294
+ } = props;
295
+
296
+ const containerSize = sizeMap[size];
297
+ const count = 10;
298
+ const innerRadius = 0.38; // start at 38% from center (larger hollow area)
299
+ const spokeLength = containerSize * 0.22;
300
+
301
+ return (
302
+ <div
303
+ className={clsx(
304
+ `${prefixCls}-indicator`,
305
+ `${prefixCls}-indicator-wheel`,
306
+ classNames?.indicator,
307
+ )}
308
+ style={{
309
+ width: width || containerSize,
310
+ height: height || containerSize,
311
+ ...styles?.indicator,
312
+ }}
313
+ >
314
+ <div className={`${prefixCls}-wheel-spokes`}>
315
+ {Array.from({ length: count }, (_, i) => {
316
+ const angle = (i * 360) / count;
317
+ const rad = (angle * Math.PI) / 180;
318
+ // Position each spoke: starts at innerRadius from center
319
+ const cx = containerSize / 2;
320
+ const cy = containerSize / 2;
321
+ const x = cx + innerRadius * containerSize * Math.sin(rad);
322
+ const y = cy - innerRadius * containerSize * Math.cos(rad);
323
+
324
+ return (
325
+ <div
326
+ key={i}
327
+ className={`${prefixCls}-wheel-spoke`}
328
+ style={{
329
+ top: y,
330
+ left: x,
331
+ height: spokeLength,
332
+ marginLeft: -1,
333
+ transform: `rotate(${angle}deg)`,
334
+ transformOrigin: 'top center',
335
+ animationDelay: `${(i * 1.2) / count}s`,
336
+ backgroundColor: color,
337
+ }}
338
+ />
339
+ );
340
+ })}
341
+ </div>
342
+ </div>
343
+ );
344
+ };
345
+
191
346
  interface IndicatorProps extends SpinProps {
192
- variant?: 'dot' | 'ring' | 'spokes';
347
+ variant?: 'dot' | 'ring' | 'spokes' | 'bounce' | 'pulse' | 'wheel';
193
348
  }
194
349
 
195
350
  const Indicator: React.FC<IndicatorProps> = ({ variant = 'dot', ...props }) => {
@@ -199,6 +354,15 @@ const Indicator: React.FC<IndicatorProps> = ({ variant = 'dot', ...props }) => {
199
354
  if (variant === 'spokes') {
200
355
  return <SpokesSpinner {...props} />;
201
356
  }
357
+ if (variant === 'bounce') {
358
+ return <BounceSpinner {...props} />;
359
+ }
360
+ if (variant === 'pulse') {
361
+ return <PulseSpinner {...props} />;
362
+ }
363
+ if (variant === 'wheel') {
364
+ return <WheelSpinner {...props} />;
365
+ }
202
366
  return <DotSpinner {...props} />;
203
367
  };
204
368
 
@@ -77,7 +77,7 @@ export type SpinProps = DataAttributeProps & {
77
77
  /**
78
78
  * Indicator variant
79
79
  * */
80
- variant?: 'dot' | 'ring' | 'spokes';
80
+ variant?: 'dot' | 'ring' | 'spokes' | 'bounce' | 'pulse' | 'wheel';
81
81
  /**
82
82
  * Loading indicator
83
83
  */
@@ -69,6 +69,64 @@
69
69
  animation: yee-spin-spokes-fade 1.2s linear infinite;
70
70
  }
71
71
  }
72
+
73
+ &-bounce {
74
+ @{pls}-bounce {
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: center;
78
+ width: 100%;
79
+ height: 100%;
80
+ gap: 3px;
81
+ }
82
+
83
+ @{pls}-bounce-dot {
84
+ display: inline-block;
85
+ background-color: var(--m-indicator-dot-bg-color);
86
+ border-radius: 50%;
87
+ animation: yee-spin-bounce 0.6s ease-in-out infinite alternate;
88
+ }
89
+ }
90
+
91
+ &-pulse {
92
+ @{pls}-pulse-circle {
93
+ position: absolute;
94
+ top: 0;
95
+ left: 0;
96
+ width: 100%;
97
+ height: 100%;
98
+ border-radius: 50%;
99
+ background-color: var(--m-indicator-dot-bg-color);
100
+ opacity: 0.6;
101
+ animation: yee-spin-pulse 1.5s ease-in-out infinite;
102
+
103
+ &-delay {
104
+ animation-delay: 0.5s;
105
+ }
106
+ }
107
+ }
108
+
109
+ &-wheel {
110
+ @{pls}-wheel-hub {
111
+ display: none;
112
+ }
113
+
114
+ @{pls}-wheel-spokes {
115
+ position: relative;
116
+ width: 100%;
117
+ height: 100%;
118
+ }
119
+
120
+ @{pls}-wheel-spoke {
121
+ position: absolute;
122
+ left: 50%;
123
+ width: 2px;
124
+ margin-left: -1px;
125
+ background-color: var(--m-indicator-dot-bg-color);
126
+ border-radius: 1px;
127
+ animation: yee-spin-spokes-fade 1.2s linear infinite;
128
+ }
129
+ }
72
130
  }
73
131
 
74
132
  &-tip {
@@ -168,3 +226,31 @@
168
226
  opacity: 0.15;
169
227
  }
170
228
  }
229
+
230
+ @keyframes yee-spin-bounce {
231
+ 0% {
232
+ transform: translateY(25%);
233
+ opacity: 0.4;
234
+ }
235
+
236
+ 100% {
237
+ transform: translateY(-25%);
238
+ opacity: 1;
239
+ }
240
+ }
241
+
242
+ @keyframes yee-spin-pulse {
243
+ 0% {
244
+ transform: scale(0);
245
+ opacity: 0.6;
246
+ }
247
+
248
+ 50% {
249
+ opacity: 0.3;
250
+ }
251
+
252
+ 100% {
253
+ transform: scale(1);
254
+ opacity: 0;
255
+ }
256
+ }
@@ -0,0 +1,92 @@
1
+ import type { ColumnProps } from '@rainbow-oh/yee-c';
2
+ import { Table } from '@rainbow-oh/yee-c';
3
+ import React from 'react';
4
+
5
+ const columns: ColumnProps[] = [
6
+ {
7
+ title: 'Name',
8
+ dataIndex: 'name',
9
+ key: 'name',
10
+ fixed: 'left',
11
+ width: 140,
12
+ },
13
+ {
14
+ title: 'Age',
15
+ dataIndex: 'age',
16
+ key: 'age',
17
+ fixed: 'left',
18
+ width: 100,
19
+ },
20
+ {
21
+ title: 'Address',
22
+ dataIndex: 'address',
23
+ key: 'address',
24
+ width: 240,
25
+ },
26
+ {
27
+ title: 'Company',
28
+ dataIndex: 'company',
29
+ key: 'company',
30
+ width: 180,
31
+ },
32
+ {
33
+ title: 'Department',
34
+ dataIndex: 'department',
35
+ key: 'department',
36
+ width: 180,
37
+ },
38
+ {
39
+ title: 'Email',
40
+ dataIndex: 'email',
41
+ key: 'email',
42
+ width: 240,
43
+ },
44
+ {
45
+ title: 'Action',
46
+ key: 'action',
47
+ fixed: 'right',
48
+ width: 100,
49
+ render: (record) => <a onClick={() => console.log(record)}>View</a>,
50
+ },
51
+ ];
52
+
53
+ const dataSource = [
54
+ {
55
+ key: '1',
56
+ name: 'John Brown',
57
+ age: 32,
58
+ address: 'New York No. 1 Lake Park',
59
+ company: 'Acme Inc.',
60
+ department: 'Engineering',
61
+ email: 'john.brown@example.com',
62
+ },
63
+ {
64
+ key: '2',
65
+ name: 'Jim Green',
66
+ age: 42,
67
+ address: 'London No. 1 Lake Park',
68
+ company: 'Globex',
69
+ department: 'Marketing',
70
+ email: 'jim.green@example.com',
71
+ },
72
+ {
73
+ key: '3',
74
+ name: 'Joe Black',
75
+ age: 28,
76
+ address: 'Sidney No. 1 Lake Park',
77
+ company: 'Initech',
78
+ department: 'Product',
79
+ email: 'joe.black@example.com',
80
+ },
81
+ ];
82
+
83
+ export default () => (
84
+ <Table
85
+ columns={columns}
86
+ dataSource={dataSource}
87
+ rowKey="key"
88
+ pagination={false}
89
+ scroll={{ x: 1180 }}
90
+ tableLayout="fixed"
91
+ />
92
+ );
@@ -31,6 +31,7 @@ export default function useColumns({
31
31
  columns,
32
32
  rowSelection,
33
33
  expandable,
34
+ measuredColumnWidths,
34
35
  }: {
35
36
  children?:
36
37
  | React.ReactElement<ColumnProps>
@@ -38,6 +39,7 @@ export default function useColumns({
38
39
  columns: ColumnProps[];
39
40
  rowSelection?: RowSelectionType;
40
41
  expandable?: ExpandableType;
42
+ measuredColumnWidths?: number[];
41
43
  }) {
42
44
  const childColumns: Array<ColumnProps> | null = useMemo(() => {
43
45
  return children
@@ -53,10 +55,10 @@ export default function useColumns({
53
55
  []) as WrapedColumnProps[];
54
56
  const tree = injectSelectionExpand(base, rowSelection, expandable);
55
57
  const leaves = flattenLeafColumns(tree);
56
- const wraped = handleColumns(leaves);
58
+ const wraped = handleColumns(leaves, measuredColumnWidths);
57
59
  const rows = parseHeaderRows(tree, wraped);
58
60
  return { wrapedColumns: wraped, headerRows: rows };
59
- }, [childColumns, columns, rowSelection, expandable]);
61
+ }, [childColumns, columns, rowSelection, expandable, measuredColumnWidths]);
60
62
 
61
63
  return {
62
64
  wrapedColumns,
@@ -23,6 +23,7 @@ A table displays rows of data.
23
23
  <code src="./demo/pagination.tsx" title="Pagination" description="Table with pagination"></code>
24
24
  <code src="./demo/column-filter.tsx" title="column filter" description="Table column filter"></code>
25
25
  <code src="./demo/grouping.tsx" title="Grouping" description="Multi-level header"></code>
26
+ <code src="./demo/fixed.tsx" title="Fixed Columns" description="Fix columns on both sides and scroll horizontally to see the effect"></code>
26
27
  <code src="./demo/components-override.tsx" title="components override" description="tbody / row rendering that can be taken over by external libs (e.g. dnd-kit)"></code>
27
28
  ## API
28
29
 
@@ -24,6 +24,7 @@ toc: 'content'
24
24
  <code src="./demo/pagination.tsx" title="分页" description="带分页的表格"></code>
25
25
  <code src="./demo/merge-cell.tsx" title="合并单元格" description="合并单元格的表格"></code>
26
26
  <code src="./demo/grouping.tsx" title="表头分组" description="多级表头"></code>
27
+ <code src="./demo/fixed.tsx" title="固定列" description="固定表格左右列,横向滚动可查看效果"></code>
27
28
  <code src="./demo/summary.tsx" title="统计" description="表格的统计行"></code>
28
29
  <code src="./demo/filter.tsx" title="筛选" description="表格的筛选功能"></code>
29
30
  <code src="./demo/column-filter.tsx" title="列筛选" description="表格的列筛选功能"></code>