@rainbow-oh/yee-c 0.14.7 → 0.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.
- package/dist/cjs/Form/index.d.ts +1 -1
- package/dist/cjs/Input/style/index.less +1 -0
- package/dist/cjs/InputNumber/demo/basic.js +1 -1
- package/dist/cjs/InputNumber/input-number.js +17 -4
- package/dist/cjs/InputNumber/interface.d.ts +3 -3
- package/dist/cjs/InputNumber/style/index.less +1 -0
- package/dist/cjs/Select/hooks/useSelectKeyboard.js +5 -2
- package/dist/cjs/Selector/selector.js +6 -3
- package/dist/cjs/TableSelect/hooks/useTableSelectKeyboard.d.ts +27 -0
- package/dist/cjs/TableSelect/hooks/useTableSelectKeyboard.js +128 -0
- package/dist/cjs/TableSelect/interface.d.ts +9 -4
- package/dist/cjs/TableSelect/internal-table.js +27 -14
- package/dist/cjs/TableSelect/style/index.less +3 -11
- package/dist/cjs/TableSelect/table-select.js +40 -3
- package/dist/cjs/style/size.css +1 -1
- package/dist/cjs/style/themes.css +1 -1
- package/dist/cjs/style/variables.css +2 -2
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/Form/index.d.ts +1 -1
- package/dist/esm/Input/style/index.less +1 -0
- package/dist/esm/InputNumber/demo/basic.js +1 -1
- package/dist/esm/InputNumber/input-number.js +20 -4
- package/dist/esm/InputNumber/interface.d.ts +3 -3
- package/dist/esm/InputNumber/style/index.less +1 -0
- package/dist/esm/Select/hooks/useSelectKeyboard.js +7 -2
- package/dist/esm/Selector/selector.js +10 -5
- package/dist/esm/TableSelect/hooks/useTableSelectKeyboard.d.ts +27 -0
- package/dist/esm/TableSelect/hooks/useTableSelectKeyboard.js +132 -0
- package/dist/esm/TableSelect/interface.d.ts +9 -4
- package/dist/esm/TableSelect/internal-table.js +6 -2
- package/dist/esm/TableSelect/style/index.less +3 -11
- package/dist/esm/TableSelect/table-select.js +36 -3
- package/dist/esm/style/size.css +1 -1
- package/dist/esm/style/themes.css +1 -1
- package/dist/esm/style/variables.css +2 -2
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/umd/yee-c.min.css +2 -2
- package/dist/umd/yee-c.min.js +1 -1
- package/package.json +1 -1
- package/src/Form/index.ts +4 -0
- package/src/Input/style/index.less +1 -0
- package/src/InputNumber/demo/basic.tsx +1 -1
- package/src/InputNumber/index.en-US.md +2 -2
- package/src/InputNumber/index.zh-CN.md +2 -2
- package/src/InputNumber/input-number.tsx +27 -6
- package/src/InputNumber/interface.ts +3 -3
- package/src/InputNumber/style/index.less +1 -0
- package/src/Select/hooks/useSelectKeyboard.ts +7 -2
- package/src/Selector/selector.tsx +10 -5
- package/src/TableSelect/hooks/useTableSelectKeyboard.ts +141 -0
- package/src/TableSelect/index.en-US.md +47 -44
- package/src/TableSelect/index.zh-CN.md +47 -44
- package/src/TableSelect/interface.ts +9 -4
- package/src/TableSelect/internal-table.tsx +14 -6
- package/src/TableSelect/style/index.less +3 -11
- package/src/TableSelect/table-select.tsx +45 -3
- package/src/style/size.css +1 -1
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/Form/index.ts
CHANGED
|
@@ -63,8 +63,8 @@ Enter a number within certain range with the mouse or keyboard.
|
|
|
63
63
|
| Property | Type | Description | Default |
|
|
64
64
|
| --- | --- | --- | --- |
|
|
65
65
|
| prefixCls | `string` | Custom class name prefix | - |
|
|
66
|
-
| value | `number \| null` | Current value | - |
|
|
67
|
-
| defaultValue | `number \| null` | Default value | - |
|
|
66
|
+
| value | `number \| string \| null` | Current value (`''` is treated as empty and never renders as 0 with a formatter) | - |
|
|
67
|
+
| defaultValue | `number \| string \| null` | Default value | - |
|
|
68
68
|
| min | `number` | Minimum value | -Infinity |
|
|
69
69
|
| max | `number` | Maximum value | Infinity |
|
|
70
70
|
| step | `number` | Step value | `1` |
|
|
@@ -67,8 +67,8 @@ toc: 'content'
|
|
|
67
67
|
| 属性名 | 类型 | 描述 | 默认值 |
|
|
68
68
|
| --- | --- | --- | --- |
|
|
69
69
|
| prefixCls | `string` | 自定义类名前缀 | - |
|
|
70
|
-
| value | `number \| null` |
|
|
71
|
-
| defaultValue | `number \| null` | 默认值 | - |
|
|
70
|
+
| value | `number \| string \| null` | 受控的值(`''` 视为空值,配 formatter 也不会渲染成 0) | - |
|
|
71
|
+
| defaultValue | `number \| string \| null` | 默认值 | - |
|
|
72
72
|
| min | `number` | 最小值 | -Infinity |
|
|
73
73
|
| max | `number` | 最大值 | Infinity |
|
|
74
74
|
| step | `number` | 步长 | `1` |
|
|
@@ -49,7 +49,7 @@ const InputNumber = forwardRef<HTMLInputElement, InputNumberProps>(
|
|
|
49
49
|
...rest
|
|
50
50
|
} = props;
|
|
51
51
|
|
|
52
|
-
const [mergedValue, setMergedValue] = useMergedState<number | null>(null, {
|
|
52
|
+
const [mergedValue, setMergedValue] = useMergedState<number | string | null>(null, {
|
|
53
53
|
value,
|
|
54
54
|
defaultValue,
|
|
55
55
|
});
|
|
@@ -57,9 +57,24 @@ const InputNumber = forwardRef<HTMLInputElement, InputNumberProps>(
|
|
|
57
57
|
const [focused, setFocused] = useState(false);
|
|
58
58
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
59
59
|
|
|
60
|
+
/** 字符串值(表单 store 常见)参与算术/比较前转数字;不可解析返回 null */
|
|
61
|
+
function toNumber(val: number | string | null | undefined): number | null {
|
|
62
|
+
if (val === null || val === undefined || val === '') return null;
|
|
63
|
+
const n = Number(val);
|
|
64
|
+
return Number.isNaN(n) ? null : n;
|
|
65
|
+
}
|
|
66
|
+
|
|
60
67
|
// Format value
|
|
61
|
-
function formatValue(val: number | null | undefined): string {
|
|
62
|
-
|
|
68
|
+
function formatValue(val: number | string | null | undefined): string {
|
|
69
|
+
// '' 与 null/undefined 同为空值:Number('') === 0,若不拦截会被
|
|
70
|
+
// formatter/precision 格式化成 '0'(如全局千分位 formatter 场景)
|
|
71
|
+
if (
|
|
72
|
+
val === null ||
|
|
73
|
+
val === undefined ||
|
|
74
|
+
val === '' ||
|
|
75
|
+
isNaN(val as number)
|
|
76
|
+
)
|
|
77
|
+
return '';
|
|
63
78
|
|
|
64
79
|
let formattedVal =
|
|
65
80
|
precision !== undefined ? Number(val).toFixed(precision) : val;
|
|
@@ -149,7 +164,7 @@ const InputNumber = forwardRef<HTMLInputElement, InputNumberProps>(
|
|
|
149
164
|
if (disabled || readOnly) return;
|
|
150
165
|
|
|
151
166
|
const offset = type === 'up' ? step : -step;
|
|
152
|
-
const currentValue = mergedValue ?? 0;
|
|
167
|
+
const currentValue = toNumber(mergedValue) ?? 0;
|
|
153
168
|
const newValue = currentValue + offset;
|
|
154
169
|
|
|
155
170
|
updateValue(newValue);
|
|
@@ -259,7 +274,10 @@ const InputNumber = forwardRef<HTMLInputElement, InputNumberProps>(
|
|
|
259
274
|
{
|
|
260
275
|
[`${prefixCls}-handler-disabled`]:
|
|
261
276
|
disabled ||
|
|
262
|
-
(
|
|
277
|
+
(() => {
|
|
278
|
+
const n = toNumber(mergedValue);
|
|
279
|
+
return n !== null && n >= max;
|
|
280
|
+
})(),
|
|
263
281
|
},
|
|
264
282
|
)}
|
|
265
283
|
onClick={() => handleStep('up')}
|
|
@@ -273,7 +291,10 @@ const InputNumber = forwardRef<HTMLInputElement, InputNumberProps>(
|
|
|
273
291
|
{
|
|
274
292
|
[`${prefixCls}-handler-disabled`]:
|
|
275
293
|
disabled ||
|
|
276
|
-
(
|
|
294
|
+
(() => {
|
|
295
|
+
const n = toNumber(mergedValue);
|
|
296
|
+
return n !== null && n <= min;
|
|
297
|
+
})(),
|
|
277
298
|
},
|
|
278
299
|
)}
|
|
279
300
|
onClick={() => handleStep('down')}
|
|
@@ -34,13 +34,13 @@ export interface InputNumberProps extends Omit<
|
|
|
34
34
|
*/
|
|
35
35
|
size?: 'small' | 'default' | 'large';
|
|
36
36
|
/**
|
|
37
|
-
* Controlled value
|
|
37
|
+
* Controlled value('' 视为空值,配合 formatter 不会渲染成 0)
|
|
38
38
|
*/
|
|
39
|
-
value?: number | null;
|
|
39
|
+
value?: number | string | null;
|
|
40
40
|
/**
|
|
41
41
|
* Default value
|
|
42
42
|
*/
|
|
43
|
-
defaultValue?: number | null;
|
|
43
|
+
defaultValue?: number | string | null;
|
|
44
44
|
/**
|
|
45
45
|
* Minimum value
|
|
46
46
|
*/
|
|
@@ -261,8 +261,13 @@ export default function useSelectKeyboard({
|
|
|
261
261
|
handleEnter();
|
|
262
262
|
break;
|
|
263
263
|
case 'Escape':
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
// Only swallow Escape while open so outer layers (e.g. a Dialog's
|
|
265
|
+
// useEsc listening on document) still receive it when closed.
|
|
266
|
+
if (open) {
|
|
267
|
+
event.preventDefault();
|
|
268
|
+
event.stopPropagation();
|
|
269
|
+
handleEscape();
|
|
270
|
+
}
|
|
266
271
|
break;
|
|
267
272
|
default:
|
|
268
273
|
}
|
|
@@ -284,12 +284,17 @@ const Selector = React.forwardRef(
|
|
|
284
284
|
aria-disabled={disabled || undefined}
|
|
285
285
|
onKeyDown={(event) => {
|
|
286
286
|
if (disabled) return;
|
|
287
|
-
//
|
|
288
|
-
if (
|
|
289
|
-
|
|
287
|
+
// Enter opens the dropdown while it is closed
|
|
288
|
+
if (event.key === 'Enter' && !open && onOpenChange) {
|
|
289
|
+
event.preventDefault();
|
|
290
|
+
onOpenChange(true);
|
|
291
|
+
}
|
|
292
|
+
// Input forwards this handler for its own keydowns; handling them
|
|
293
|
+
// here too would fire the handler twice per keypress. Only handle
|
|
294
|
+
// events that originate on the container (non-searchable focus).
|
|
295
|
+
if (event.target !== inputRef.current) {
|
|
296
|
+
externalOnKeyDown?.(event as React.KeyboardEvent<HTMLInputElement>);
|
|
290
297
|
}
|
|
291
|
-
// Also call external onKeyDown if provided
|
|
292
|
-
externalOnKeyDown?.(event as React.KeyboardEvent<HTMLInputElement>);
|
|
293
298
|
}}
|
|
294
299
|
ref={ref}
|
|
295
300
|
>
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import type { TableSelectDataType } from '../interface';
|
|
3
|
+
|
|
4
|
+
type KeyType = string | number;
|
|
5
|
+
|
|
6
|
+
interface UseTableSelectKeyboardParams {
|
|
7
|
+
open: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
dataSource: Array<TableSelectDataType>;
|
|
10
|
+
rowKey: string | ((record: any) => string);
|
|
11
|
+
selectionType: 'radio' | 'checkbox';
|
|
12
|
+
selectedRowKeys: Array<KeyType>;
|
|
13
|
+
searchValue: string;
|
|
14
|
+
onSelect: (keys: Array<KeyType>, rows: Array<TableSelectDataType>) => void;
|
|
15
|
+
onClose: () => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Keyboard navigation for the popup table. The highlight is positional (like a
|
|
20
|
+
* hover cursor): `activeRow` is a rendered row index, and Space selects the
|
|
21
|
+
* record displayed there. The rendered order is the filter→sort→paginate
|
|
22
|
+
* result inside Table and is not derivable from `dataSource`, so the row count
|
|
23
|
+
* and the highlighted row's key are both read from the popup DOM.
|
|
24
|
+
*/
|
|
25
|
+
export default function useTableSelectKeyboard({
|
|
26
|
+
open,
|
|
27
|
+
disabled,
|
|
28
|
+
dataSource,
|
|
29
|
+
rowKey,
|
|
30
|
+
selectionType,
|
|
31
|
+
selectedRowKeys,
|
|
32
|
+
searchValue,
|
|
33
|
+
onSelect,
|
|
34
|
+
onClose,
|
|
35
|
+
}: UseTableSelectKeyboardParams) {
|
|
36
|
+
const popupRef = useRef<HTMLDivElement | null>(null);
|
|
37
|
+
// 1-based index of the highlighted row (`tr[data-row-index]`), 0 = none.
|
|
38
|
+
const [activeRow, setActiveRow] = useState(0);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
setActiveRow(0);
|
|
42
|
+
}, [open, searchValue]);
|
|
43
|
+
|
|
44
|
+
const getRecordKey = (item: TableSelectDataType) =>
|
|
45
|
+
typeof rowKey === 'function' ? rowKey(item) : item[rowKey];
|
|
46
|
+
|
|
47
|
+
const getRowCount = () =>
|
|
48
|
+
popupRef.current?.querySelectorAll('tr[data-row-index]').length ?? 0;
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!open || activeRow < 1) return;
|
|
52
|
+
const rowEl = popupRef.current?.querySelector(
|
|
53
|
+
`tr[data-row-index="${activeRow}"]`,
|
|
54
|
+
) as HTMLElement | null;
|
|
55
|
+
if (!rowEl) return;
|
|
56
|
+
// Manual scroll instead of scrollIntoView: the popup renders in a portal,
|
|
57
|
+
// and scrollIntoView would scroll the page as well as the popup.
|
|
58
|
+
let parent = rowEl.parentElement;
|
|
59
|
+
while (parent && parent !== popupRef.current) {
|
|
60
|
+
const { overflowY } = window.getComputedStyle(parent);
|
|
61
|
+
if (
|
|
62
|
+
/(auto|scroll)/.test(overflowY) &&
|
|
63
|
+
parent.scrollHeight > parent.clientHeight
|
|
64
|
+
) {
|
|
65
|
+
const parentRect = parent.getBoundingClientRect();
|
|
66
|
+
const rowRect = rowEl.getBoundingClientRect();
|
|
67
|
+
if (rowRect.bottom > parentRect.bottom) {
|
|
68
|
+
parent.scrollTop += rowRect.bottom - parentRect.bottom;
|
|
69
|
+
} else if (rowRect.top < parentRect.top) {
|
|
70
|
+
parent.scrollTop -= parentRect.top - rowRect.top;
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
parent = parent.parentElement;
|
|
75
|
+
}
|
|
76
|
+
}, [activeRow, open]);
|
|
77
|
+
|
|
78
|
+
const selectActiveRow = () => {
|
|
79
|
+
const rowEl = popupRef.current?.querySelector(
|
|
80
|
+
`tr[data-row-index="${activeRow}"]`,
|
|
81
|
+
);
|
|
82
|
+
const inputEl = rowEl?.querySelector(
|
|
83
|
+
'input[type="radio"],input[type="checkbox"]',
|
|
84
|
+
) as HTMLInputElement | null;
|
|
85
|
+
if (!inputEl || inputEl.disabled) return;
|
|
86
|
+
|
|
87
|
+
const record = dataSource.find(
|
|
88
|
+
(item) => String(getRecordKey(item)) === inputEl.value,
|
|
89
|
+
);
|
|
90
|
+
if (!record) return;
|
|
91
|
+
const key = getRecordKey(record);
|
|
92
|
+
|
|
93
|
+
if (selectionType === 'radio') {
|
|
94
|
+
// Same shape as the click path: arrays, normalized by the consumer.
|
|
95
|
+
onSelect([key], [record]);
|
|
96
|
+
onClose();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const checked = selectedRowKeys.some((k) => String(k) === String(key));
|
|
101
|
+
const nextKeys = checked
|
|
102
|
+
? selectedRowKeys.filter((k) => String(k) !== String(key))
|
|
103
|
+
: [...selectedRowKeys, key];
|
|
104
|
+
const rows = dataSource.filter((item) =>
|
|
105
|
+
nextKeys.some((k) => String(getRecordKey(item)) === String(k)),
|
|
106
|
+
);
|
|
107
|
+
onSelect(nextKeys, rows);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
111
|
+
if (!open || disabled) return;
|
|
112
|
+
switch (event.key) {
|
|
113
|
+
case 'ArrowDown':
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
setActiveRow(Math.min(activeRow + 1, getRowCount()));
|
|
116
|
+
break;
|
|
117
|
+
case 'ArrowUp':
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
setActiveRow(activeRow <= 1 ? getRowCount() : activeRow - 1);
|
|
120
|
+
break;
|
|
121
|
+
case ' ':
|
|
122
|
+
// With nothing highlighted, space keeps its native input behavior.
|
|
123
|
+
if (activeRow > 0) {
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
selectActiveRow();
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
case 'Escape':
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
// Stop the event from reaching outer layers (e.g. a Dialog's useEsc
|
|
131
|
+
// listening on document) so only the dropdown closes.
|
|
132
|
+
event.stopPropagation();
|
|
133
|
+
onClose();
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return { popupRef, activeRow, handleKeyDown };
|
|
141
|
+
}
|
|
@@ -31,45 +31,45 @@ A component for selecting one or more options from table data, combining feature
|
|
|
31
31
|
|
|
32
32
|
### TableSelectProps
|
|
33
33
|
|
|
34
|
-
| Property
|
|
35
|
-
|
|
|
36
|
-
| prefixCls
|
|
37
|
-
| className
|
|
38
|
-
| style
|
|
39
|
-
| rowKey
|
|
40
|
-
| columns
|
|
41
|
-
| dataSource
|
|
42
|
-
| rowSelection
|
|
43
|
-
| value
|
|
44
|
-
| defaultValue
|
|
45
|
-
| disabled
|
|
46
|
-
| loading
|
|
47
|
-
| placement
|
|
48
|
-
| searchable
|
|
49
|
-
| searchOnInput
|
|
50
|
-
| allowClear
|
|
51
|
-
| closable
|
|
52
|
-
| placeholder
|
|
53
|
-
| optionLabelProp | `string \| ((option:
|
|
54
|
-
| type
|
|
55
|
-
| options
|
|
56
|
-
| isShowFilter
|
|
57
|
-
| containerId
|
|
58
|
-
| io
|
|
59
|
-
| onChange
|
|
60
|
-
| onSearch
|
|
61
|
-
| onOpenChange
|
|
34
|
+
| Property | Type | Description | Default Value |
|
|
35
|
+
| --------------- | ----------------------------------------------------- | ---------------------------------------------------------- | -------------------- |
|
|
36
|
+
| prefixCls | `string` | Custom class name prefix | `'yee-table-select'` |
|
|
37
|
+
| className | `string` | Root element class name | - |
|
|
38
|
+
| style | `React.CSSProperties` | Root element inline styles | - |
|
|
39
|
+
| rowKey | `string \| ((record: any) => string)` | Unique identifier field name for data | `'id'` |
|
|
40
|
+
| columns | `Array<any>` | Table column configuration | - |
|
|
41
|
+
| dataSource | `Array<TableSelectDataType>` | Data source | - |
|
|
42
|
+
| rowSelection | `RowSelectionType` | Row selection configuration | - |
|
|
43
|
+
| value | `SelectionKeyType \| SelectionKeyType[]` | Controlled value | - |
|
|
44
|
+
| defaultValue | `SelectionKeyType \| SelectionKeyType[]` | Default value | - |
|
|
45
|
+
| disabled | `boolean` | Whether disabled | - |
|
|
46
|
+
| loading | `boolean` | Whether data is loading; displays a gray loading indicator | `false` |
|
|
47
|
+
| placement | `'bottomLeft' \| 'topLeft'` | Popup placement | `'bottomLeft'` |
|
|
48
|
+
| searchable | `boolean` | Whether searchable | `true` |
|
|
49
|
+
| searchOnInput | `boolean` | Whether to search while typing | `true` |
|
|
50
|
+
| allowClear | `boolean` | Whether allow clear | `true` |
|
|
51
|
+
| closable | `boolean` | Whether tags are closable | `true` |
|
|
52
|
+
| placeholder | `string` | Placeholder text | - |
|
|
53
|
+
| optionLabelProp | `string \| ((option: TableSelectDataType) => string)` | Option label property | `'name'` |
|
|
54
|
+
| type | `'radio' \| 'checkbox'` | Selection type | `'radio'` |
|
|
55
|
+
| options | `TagType[]` | Preset options | - |
|
|
56
|
+
| isShowFilter | `boolean` | Whether to show filter (All/Selected for multiple) | `true` |
|
|
57
|
+
| containerId | `string` | Container ID (for popup mounting) | - |
|
|
58
|
+
| io | `'out'` | Input direction | - |
|
|
59
|
+
| onChange | `(keys, data, checked, changeData) => void` | Selection change callback | - |
|
|
60
|
+
| onSearch | `(value: string, e?) => void` | Search callback | - |
|
|
61
|
+
| onOpenChange | `(open: boolean) => void` | Popup state change callback | - |
|
|
62
62
|
|
|
63
63
|
### RowSelectionType
|
|
64
64
|
|
|
65
65
|
Row selection configuration, inherited from Table component's RowSelectionType.
|
|
66
66
|
|
|
67
|
-
| Property
|
|
68
|
-
|
|
|
69
|
-
| type
|
|
70
|
-
| selectedRowKeys
|
|
71
|
-
| defaultSelectedRowKeys | `Array<SelectionKeyType> \| SelectionKeyType` | Default selected row keys
|
|
72
|
-
| onChange
|
|
67
|
+
| Property | Type | Description | Default Value |
|
|
68
|
+
| ---------------------- | --------------------------------------------- | ------------------------------- | ------------- |
|
|
69
|
+
| type | `'radio' \| 'checkbox'` | Single/multiple selection | - |
|
|
70
|
+
| selectedRowKeys | `Array<SelectionKeyType> \| SelectionKeyType` | (Controlled) selected row keys | - |
|
|
71
|
+
| defaultSelectedRowKeys | `Array<SelectionKeyType> \| SelectionKeyType` | Default selected row keys | - |
|
|
72
|
+
| onChange | `(selectedRowKeys, selectedRows) => void` | Callback when selection changes | - |
|
|
73
73
|
|
|
74
74
|
## Methods
|
|
75
75
|
|
|
@@ -77,17 +77,20 @@ Row selection configuration, inherited from Table component's RowSelectionType.
|
|
|
77
77
|
|
|
78
78
|
InternalTable is an internal component of TableSelect and typically doesn't need to be used directly.
|
|
79
79
|
|
|
80
|
-
| Property
|
|
81
|
-
|
|
|
82
|
-
| rowKey
|
|
83
|
-
| columns
|
|
84
|
-
| dataSource
|
|
85
|
-
| rowSelection | `RowSelectionType`
|
|
86
|
-
| type
|
|
87
|
-
| value
|
|
88
|
-
| isShowFilter | `boolean`
|
|
89
|
-
| visible
|
|
80
|
+
| Property | Type | Description | Default Value |
|
|
81
|
+
| ------------ | ------------------------------------------- | ---------------------------------------------------------------------- | ------------- |
|
|
82
|
+
| rowKey | `string` | Unique identifier field name for data | - |
|
|
83
|
+
| columns | `Array<any>` | Table column configuration | - |
|
|
84
|
+
| dataSource | `Array<TableSelectDataType>` | Data source | - |
|
|
85
|
+
| rowSelection | `RowSelectionType` | Row selection configuration | - |
|
|
86
|
+
| type | `'radio' \| 'checkbox'` | Selection type | - |
|
|
87
|
+
| value | `SelectedKeyType \| Array<SelectedKeyType>` | Selected value | - |
|
|
88
|
+
| isShowFilter | `boolean` | Whether to show filter | `true` |
|
|
89
|
+
| visible | `boolean` | Whether popup is visible | - |
|
|
90
|
+
| popupRef | `React.RefObject<HTMLDivElement \| null>` | Ref to the popup root element, used internally for keyboard navigation | - |
|
|
90
91
|
|
|
91
92
|
## Notes
|
|
92
93
|
|
|
94
|
+
- When the dropdown is open, keyboard is supported: `↑`/`↓` move the highlight across rows, `Space` selects/toggles the highlighted row, `Esc` closes the dropdown; the text caret always stays in the input; press `Enter` while closed to open the dropdown
|
|
95
|
+
|
|
93
96
|
- Adapted for mobile (popup constrained with max-width/height and scrollable)
|
|
@@ -31,45 +31,45 @@ toc: 'content'
|
|
|
31
31
|
|
|
32
32
|
### TableSelectProps
|
|
33
33
|
|
|
34
|
-
| 属性名
|
|
35
|
-
|
|
|
36
|
-
| prefixCls
|
|
37
|
-
| className
|
|
38
|
-
| style
|
|
39
|
-
| rowKey
|
|
40
|
-
| columns
|
|
41
|
-
| dataSource
|
|
42
|
-
| rowSelection
|
|
43
|
-
| value
|
|
44
|
-
| defaultValue
|
|
45
|
-
| disabled
|
|
46
|
-
| loading
|
|
47
|
-
| placement
|
|
48
|
-
| searchable
|
|
49
|
-
| searchOnInput
|
|
50
|
-
| allowClear
|
|
51
|
-
| closable
|
|
52
|
-
| placeholder
|
|
53
|
-
| optionLabelProp | `string \| ((option:
|
|
54
|
-
| type
|
|
55
|
-
| options
|
|
56
|
-
| isShowFilter
|
|
57
|
-
| containerId
|
|
58
|
-
| io
|
|
59
|
-
| onChange
|
|
60
|
-
| onSearch
|
|
61
|
-
| onOpenChange
|
|
34
|
+
| 属性名 | 类型 | 描述 | 默认值 |
|
|
35
|
+
| --------------- | ----------------------------------------------------- | ---------------------------------------- | -------------------- |
|
|
36
|
+
| prefixCls | `string` | 自定义类名前缀 | `'yee-table-select'` |
|
|
37
|
+
| className | `string` | 根元素类名 | - |
|
|
38
|
+
| style | `React.CSSProperties` | 根元素行内样式 | - |
|
|
39
|
+
| rowKey | `string \| ((record: any) => string)` | 数据的唯一标识字段名 | `'id'` |
|
|
40
|
+
| columns | `Array<any>` | 表格列的配置信息 | - |
|
|
41
|
+
| dataSource | `Array<TableSelectDataType>` | 数据源 | - |
|
|
42
|
+
| rowSelection | `RowSelectionType` | 行选择配置 | - |
|
|
43
|
+
| value | `SelectionKeyType \| SelectionKeyType[]` | 受控值 | - |
|
|
44
|
+
| defaultValue | `SelectionKeyType \| SelectionKeyType[]` | 默认值 | - |
|
|
45
|
+
| disabled | `boolean` | 是否禁用 | - |
|
|
46
|
+
| loading | `boolean` | 是否处于加载状态,加载时显示灰色加载图标 | `false` |
|
|
47
|
+
| placement | `'bottomLeft' \| 'topLeft'` | 弹出层位置 | `'bottomLeft'` |
|
|
48
|
+
| searchable | `boolean` | 是否可搜索 | `true` |
|
|
49
|
+
| searchOnInput | `boolean` | 是否边输入边搜索 | `true` |
|
|
50
|
+
| allowClear | `boolean` | 是否允许清除 | `true` |
|
|
51
|
+
| closable | `boolean` | 标签是否可关闭 | `true` |
|
|
52
|
+
| placeholder | `string` | 占位符文本 | - |
|
|
53
|
+
| optionLabelProp | `string \| ((option: TableSelectDataType) => string)` | 选项标签属性 | `'name'` |
|
|
54
|
+
| type | `'radio' \| 'checkbox'` | 选择类型 | `'radio'` |
|
|
55
|
+
| options | `TagType[]` | 预设选项 | - |
|
|
56
|
+
| isShowFilter | `boolean` | 是否显示过滤器(多选时 All/Selected) | `true` |
|
|
57
|
+
| containerId | `string` | 容器 ID(用于弹出层挂载) | - |
|
|
58
|
+
| io | `'out'` | 输入方向 | - |
|
|
59
|
+
| onChange | `(keys, data, checked, changeData) => void` | 选中变更回调 | - |
|
|
60
|
+
| onSearch | `(value: string, e?) => void` | 搜索回调 | - |
|
|
61
|
+
| onOpenChange | `(open: boolean) => void` | 弹出层状态变更回调 | - |
|
|
62
62
|
|
|
63
63
|
### RowSelectionType
|
|
64
64
|
|
|
65
65
|
表格行选择配置,继承自 Table 组件的 RowSelectionType。
|
|
66
66
|
|
|
67
|
-
| 属性名
|
|
68
|
-
|
|
|
69
|
-
| type
|
|
70
|
-
| selectedRowKeys
|
|
71
|
-
| defaultSelectedRowKeys | `Array<SelectionKeyType> \| SelectionKeyType` | 默认选中的行keys
|
|
72
|
-
| onChange
|
|
67
|
+
| 属性名 | 类型 | 描述 | 默认值 |
|
|
68
|
+
| ---------------------- | --------------------------------------------- | ---------------------- | ------ |
|
|
69
|
+
| type | `'radio' \| 'checkbox'` | 单选/多选 | - |
|
|
70
|
+
| selectedRowKeys | `Array<SelectionKeyType> \| SelectionKeyType` | (受控)选中的行keys | - |
|
|
71
|
+
| defaultSelectedRowKeys | `Array<SelectionKeyType> \| SelectionKeyType` | 默认选中的行keys | - |
|
|
72
|
+
| onChange | `(selectedRowKeys, selectedRows) => void` | 选中项发生变化时的回调 | - |
|
|
73
73
|
|
|
74
74
|
## 方法
|
|
75
75
|
|
|
@@ -77,17 +77,20 @@ toc: 'content'
|
|
|
77
77
|
|
|
78
78
|
InternalTable 组件是 TableSelect 的内部组件,通常不需要直接使用。
|
|
79
79
|
|
|
80
|
-
| 属性名
|
|
81
|
-
|
|
|
82
|
-
| rowKey
|
|
83
|
-
| columns
|
|
84
|
-
| dataSource
|
|
85
|
-
| rowSelection | `RowSelectionType`
|
|
86
|
-
| type
|
|
87
|
-
| value
|
|
88
|
-
| isShowFilter | `boolean`
|
|
89
|
-
| visible
|
|
80
|
+
| 属性名 | 类型 | 描述 | 默认值 |
|
|
81
|
+
| ------------ | ------------------------------------------- | ---------------------------------- | ------ |
|
|
82
|
+
| rowKey | `string` | 数据的唯一标识字段名 | - |
|
|
83
|
+
| columns | `Array<any>` | 表格列的配置信息 | - |
|
|
84
|
+
| dataSource | `Array<TableSelectDataType>` | 数据源 | - |
|
|
85
|
+
| rowSelection | `RowSelectionType` | 行选择配置 | - |
|
|
86
|
+
| type | `'radio' \| 'checkbox'` | 选择类型 | - |
|
|
87
|
+
| value | `SelectedKeyType \| Array<SelectedKeyType>` | 选中的值 | - |
|
|
88
|
+
| isShowFilter | `boolean` | 是否显示过滤器 | `true` |
|
|
89
|
+
| visible | `boolean` | 弹出层是否可见 | - |
|
|
90
|
+
| popupRef | `React.RefObject<HTMLDivElement \| null>` | 弹层根元素 ref,供键盘导航内部使用 | - |
|
|
90
91
|
|
|
91
92
|
## 注意事项
|
|
92
93
|
|
|
94
|
+
- 下拉展开后支持键盘操作:`↑`/`↓` 在行间移动高亮,`空格` 选中/取消勾选高亮行,`Esc` 关闭下拉;输入光标始终保留在输入框内;收起时按 `回车` 可展开下拉
|
|
95
|
+
|
|
93
96
|
- 已适配移动端(弹窗限制最大宽高并支持滚动)
|
|
@@ -10,7 +10,7 @@ type SelectedKeyType = string | number;
|
|
|
10
10
|
/**
|
|
11
11
|
* Data item type
|
|
12
12
|
*/
|
|
13
|
-
type
|
|
13
|
+
export type TableSelectDataType = {
|
|
14
14
|
[propName: string]: any;
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -42,7 +42,7 @@ export interface InternalTableProps {
|
|
|
42
42
|
/**
|
|
43
43
|
* Data source
|
|
44
44
|
*/
|
|
45
|
-
dataSource: Array<
|
|
45
|
+
dataSource: Array<TableSelectDataType>;
|
|
46
46
|
/**
|
|
47
47
|
* Custom class name
|
|
48
48
|
*/
|
|
@@ -67,6 +67,11 @@ export interface InternalTableProps {
|
|
|
67
67
|
* Whether popup is visible (for focus trap)
|
|
68
68
|
*/
|
|
69
69
|
visible?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Ref to the popup root element, used by TableSelect for keyboard navigation
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
popupRef?: React.RefObject<HTMLDivElement | null>;
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
/**
|
|
@@ -96,7 +101,7 @@ export interface TableSelectProps
|
|
|
96
101
|
/**
|
|
97
102
|
* Data source
|
|
98
103
|
*/
|
|
99
|
-
dataSource: Array<
|
|
104
|
+
dataSource: Array<TableSelectDataType>;
|
|
100
105
|
/**
|
|
101
106
|
* Single or multiple selection
|
|
102
107
|
* @default: 'radio'
|
|
@@ -180,7 +185,7 @@ export interface TableSelectProps
|
|
|
180
185
|
* Option label property (text field for displaying labels)
|
|
181
186
|
* @default 'name'
|
|
182
187
|
*/
|
|
183
|
-
optionLabelProp?: string | ((option:
|
|
188
|
+
optionLabelProp?: string | ((option: TableSelectDataType) => string);
|
|
184
189
|
/**
|
|
185
190
|
* Selection change callback
|
|
186
191
|
* @param keys Selected keys
|