@rainbow-oh/yee-c 0.14.6 → 0.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.
- package/dist/cjs/Form/Field.js +20 -1
- package/dist/cjs/Form/Group.js +3 -1
- package/dist/cjs/Form/index.d.ts +1 -1
- package/dist/cjs/Input/style/index.less +1 -0
- 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/Selector/style/index.less +2 -2
- 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/color.css +5 -5
- package/dist/cjs/style/color.gemini.css +1 -1
- package/dist/cjs/style/size.css +1 -1
- package/dist/cjs/style/themes.css +2 -2
- package/dist/cjs/style/variables.css +7 -7
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/Form/Field.js +35 -4
- package/dist/esm/Form/Group.js +10 -6
- package/dist/esm/Form/index.d.ts +1 -1
- package/dist/esm/Input/style/index.less +1 -0
- 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/Selector/style/index.less +2 -2
- 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/color.css +5 -5
- package/dist/esm/style/color.gemini.css +1 -1
- package/dist/esm/style/size.css +1 -1
- package/dist/esm/style/themes.css +2 -2
- package/dist/esm/style/variables.css +7 -7
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/umd/yee-c.min.css +3 -3
- package/dist/umd/yee-c.min.js +1 -1
- package/package.json +1 -1
- package/src/Form/Field.required.test.tsx +146 -0
- package/src/Form/Field.tsx +32 -2
- package/src/Form/Group.tsx +7 -2
- package/src/Form/index.ts +4 -0
- package/src/Input/style/index.less +1 -0
- 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/Selector/style/index.less +2 -2
- 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/color.css +5 -5
- package/src/style/color.gemini.css +1 -1
- package/src/style/size.css +1 -1
- package/src/version.ts +1 -1
package/dist/esm/Form/Field.js
CHANGED
|
@@ -20,7 +20,7 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
|
20
20
|
import clsx from 'clsx';
|
|
21
21
|
import { HelpCircle } from 'lucide-react';
|
|
22
22
|
import { AnimatePresence, motion } from 'motion/react';
|
|
23
|
-
import React, { useContext, useLayoutEffect, useMemo, useReducer } from 'react';
|
|
23
|
+
import React, { useContext, useLayoutEffect, useMemo, useReducer, useRef } from 'react';
|
|
24
24
|
import Tooltip from "../Tooltip";
|
|
25
25
|
import FieldContext from "./FieldContext";
|
|
26
26
|
import FormContext from "./FormContext";
|
|
@@ -56,6 +56,7 @@ var Field = function Field(props) {
|
|
|
56
56
|
var _useContext = useContext(FieldContext),
|
|
57
57
|
getCallbacks = _useContext.getCallbacks,
|
|
58
58
|
getFieldStatus = _useContext.getFieldStatus,
|
|
59
|
+
getFieldValidate = _useContext.getFieldValidate,
|
|
59
60
|
getFieldValue = _useContext.getFieldValue,
|
|
60
61
|
getFieldsValue = _useContext.getFieldsValue,
|
|
61
62
|
setFieldsValue = _useContext.setFieldsValue,
|
|
@@ -84,15 +85,45 @@ var Field = function Field(props) {
|
|
|
84
85
|
var normalizedName = useMemo(function () {
|
|
85
86
|
return stringifyPath(fullFieldNamePath);
|
|
86
87
|
}, [fullFieldNamePath]);
|
|
88
|
+
|
|
89
|
+
// Registration happens once per field name, but the store (validateField)
|
|
90
|
+
// reads validation config off entity.props on every validation pass — the
|
|
91
|
+
// getter keeps those reads on the latest render's props so runtime changes
|
|
92
|
+
// to required/rules take effect.
|
|
93
|
+
var propsRef = useRef(props);
|
|
94
|
+
propsRef.current = props;
|
|
87
95
|
useLayoutEffect(function () {
|
|
88
96
|
var unregister = registerFieldEntities === null || registerFieldEntities === void 0 ? void 0 : registerFieldEntities({
|
|
89
|
-
props
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
get props() {
|
|
98
|
+
return _objectSpread(_objectSpread({}, propsRef.current), {}, {
|
|
99
|
+
name: normalizedName
|
|
100
|
+
});
|
|
101
|
+
},
|
|
92
102
|
onStoreChange: forceUpdate
|
|
93
103
|
});
|
|
94
104
|
return unregister;
|
|
95
105
|
}, [normalizedName, registerFieldEntities]);
|
|
106
|
+
|
|
107
|
+
// JSON signature (not reference) because rules is typically an inline array
|
|
108
|
+
// literal; validator functions are dropped, but the getter above already
|
|
109
|
+
// makes the next natural validation use them.
|
|
110
|
+
var validateSignature = useMemo(function () {
|
|
111
|
+
return JSON.stringify({
|
|
112
|
+
required: required,
|
|
113
|
+
rules: rules
|
|
114
|
+
});
|
|
115
|
+
}, [required, rules]);
|
|
116
|
+
var prevValidateSignatureRef = useRef(validateSignature);
|
|
117
|
+
useLayoutEffect(function () {
|
|
118
|
+
var prev = prevValidateSignatureRef.current;
|
|
119
|
+
prevValidateSignatureRef.current = validateSignature;
|
|
120
|
+
if (prev === validateSignature) return;
|
|
121
|
+
// Only re-check fields already showing a validation message — pristine
|
|
122
|
+
// fields must not start erroring just because rules changed.
|
|
123
|
+
if (getFieldValidate !== null && getFieldValidate !== void 0 && getFieldValidate(normalizedName)) {
|
|
124
|
+
void (validateField === null || validateField === void 0 ? void 0 : validateField(normalizedName));
|
|
125
|
+
}
|
|
126
|
+
}, [validateSignature, normalizedName]);
|
|
96
127
|
var isRequired = function isRequired() {
|
|
97
128
|
return Array.isArray(rules) && rules.find(function (rule) {
|
|
98
129
|
return rule.required;
|
package/dist/esm/Form/Group.js
CHANGED
|
@@ -57,7 +57,7 @@ var Group = function Group(props) {
|
|
|
57
57
|
forceValidate = _useReducer4[1]; // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
58
58
|
|
|
59
59
|
// Group validation
|
|
60
|
-
var
|
|
60
|
+
var validate = /*#__PURE__*/function () {
|
|
61
61
|
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(force) {
|
|
62
62
|
var values, errors, hasEmpty, _iterator, _step, rule, result, _ref2, _result$message;
|
|
63
63
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
@@ -165,7 +165,7 @@ var Group = function Group(props) {
|
|
|
165
165
|
while (1) switch (_context2.prev = _context2.next) {
|
|
166
166
|
case 0:
|
|
167
167
|
_context2.next = 2;
|
|
168
|
-
return
|
|
168
|
+
return validate(false);
|
|
169
169
|
case 2:
|
|
170
170
|
result = _context2.sent;
|
|
171
171
|
setErrors(result);
|
|
@@ -195,17 +195,21 @@ var Group = function Group(props) {
|
|
|
195
195
|
};
|
|
196
196
|
}, [childNames, formInstance]);
|
|
197
197
|
|
|
198
|
-
// Register group validator to FormStore
|
|
198
|
+
// Register group validator to FormStore. The closure is registered once, so
|
|
199
|
+
// it reads the latest validate (and its required/rules/childNames captures)
|
|
200
|
+
// through a ref — otherwise runtime prop changes never take effect.
|
|
201
|
+
var validateRef = useRef(validate);
|
|
202
|
+
validateRef.current = validate;
|
|
199
203
|
useEffect(function () {
|
|
200
204
|
var unregister = formInstance.registerGroupEntity(groupId, {
|
|
201
205
|
validate: function () {
|
|
202
|
-
var
|
|
206
|
+
var _validate = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(force) {
|
|
203
207
|
var result;
|
|
204
208
|
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
|
205
209
|
while (1) switch (_context3.prev = _context3.next) {
|
|
206
210
|
case 0:
|
|
207
211
|
_context3.next = 2;
|
|
208
|
-
return
|
|
212
|
+
return validateRef.current(force);
|
|
209
213
|
case 2:
|
|
210
214
|
result = _context3.sent;
|
|
211
215
|
setErrors(result);
|
|
@@ -218,7 +222,7 @@ var Group = function Group(props) {
|
|
|
218
222
|
}, _callee3);
|
|
219
223
|
}));
|
|
220
224
|
function validate(_x2) {
|
|
221
|
-
return
|
|
225
|
+
return _validate.apply(this, arguments);
|
|
222
226
|
}
|
|
223
227
|
return validate;
|
|
224
228
|
}(),
|
package/dist/esm/Form/index.d.ts
CHANGED
|
@@ -16,5 +16,5 @@ type FormInterface = typeof InternalForm & {
|
|
|
16
16
|
List: typeof List;
|
|
17
17
|
};
|
|
18
18
|
declare const Form: FormInterface;
|
|
19
|
-
export type { FieldGroupProps, FieldStatus, FieldStatusData, FormInstance, FormListProps, FormProps, Rule as FormRule, ValidateMessage, } from './interface';
|
|
19
|
+
export type { FieldGroupProps, FieldProps, FieldStatus, FieldStatusData, FieldTooltip, FormInstance, FormListField, FormListOperation, FormListProps, FormProps, Rule as FormRule, ValidateMessage, } from './interface';
|
|
20
20
|
export default Form;
|
|
@@ -225,8 +225,13 @@ export default function useSelectKeyboard(_ref) {
|
|
|
225
225
|
handleEnter();
|
|
226
226
|
break;
|
|
227
227
|
case 'Escape':
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
// Only swallow Escape while open so outer layers (e.g. a Dialog's
|
|
229
|
+
// useEsc listening on document) still receive it when closed.
|
|
230
|
+
if (open) {
|
|
231
|
+
event.preventDefault();
|
|
232
|
+
event.stopPropagation();
|
|
233
|
+
handleEscape();
|
|
234
|
+
}
|
|
230
235
|
break;
|
|
231
236
|
default:
|
|
232
237
|
}
|
|
@@ -220,12 +220,17 @@ var Selector = /*#__PURE__*/React.forwardRef(function (props, ref) {
|
|
|
220
220
|
"aria-disabled": disabled || undefined,
|
|
221
221
|
onKeyDown: function onKeyDown(event) {
|
|
222
222
|
if (disabled) return;
|
|
223
|
-
//
|
|
224
|
-
if (
|
|
225
|
-
|
|
223
|
+
// Enter opens the dropdown while it is closed
|
|
224
|
+
if (event.key === 'Enter' && !open && onOpenChange) {
|
|
225
|
+
event.preventDefault();
|
|
226
|
+
onOpenChange(true);
|
|
227
|
+
}
|
|
228
|
+
// Input forwards this handler for its own keydowns; handling them
|
|
229
|
+
// here too would fire the handler twice per keypress. Only handle
|
|
230
|
+
// events that originate on the container (non-searchable focus).
|
|
231
|
+
if (event.target !== inputRef.current) {
|
|
232
|
+
externalOnKeyDown === null || externalOnKeyDown === void 0 || externalOnKeyDown(event);
|
|
226
233
|
}
|
|
227
|
-
// Also call external onKeyDown if provided
|
|
228
|
-
externalOnKeyDown === null || externalOnKeyDown === void 0 || externalOnKeyDown(event);
|
|
229
234
|
},
|
|
230
235
|
ref: ref
|
|
231
236
|
}), /*#__PURE__*/React.createElement("div", {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { TableSelectDataType } from '../interface';
|
|
3
|
+
type KeyType = string | number;
|
|
4
|
+
interface UseTableSelectKeyboardParams {
|
|
5
|
+
open: boolean;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
dataSource: Array<TableSelectDataType>;
|
|
8
|
+
rowKey: string | ((record: any) => string);
|
|
9
|
+
selectionType: 'radio' | 'checkbox';
|
|
10
|
+
selectedRowKeys: Array<KeyType>;
|
|
11
|
+
searchValue: string;
|
|
12
|
+
onSelect: (keys: Array<KeyType>, rows: Array<TableSelectDataType>) => void;
|
|
13
|
+
onClose: () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Keyboard navigation for the popup table. The highlight is positional (like a
|
|
17
|
+
* hover cursor): `activeRow` is a rendered row index, and Space selects the
|
|
18
|
+
* record displayed there. The rendered order is the filter→sort→paginate
|
|
19
|
+
* result inside Table and is not derivable from `dataSource`, so the row count
|
|
20
|
+
* and the highlighted row's key are both read from the popup DOM.
|
|
21
|
+
*/
|
|
22
|
+
export default function useTableSelectKeyboard({ open, disabled, dataSource, rowKey, selectionType, selectedRowKeys, searchValue, onSelect, onClose, }: UseTableSelectKeyboardParams): {
|
|
23
|
+
popupRef: import("react").RefObject<HTMLDivElement | null>;
|
|
24
|
+
activeRow: number;
|
|
25
|
+
handleKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
2
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
4
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
5
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
6
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
7
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
8
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
9
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
10
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
11
|
+
import { useEffect, useRef, useState } from 'react';
|
|
12
|
+
/**
|
|
13
|
+
* Keyboard navigation for the popup table. The highlight is positional (like a
|
|
14
|
+
* hover cursor): `activeRow` is a rendered row index, and Space selects the
|
|
15
|
+
* record displayed there. The rendered order is the filter→sort→paginate
|
|
16
|
+
* result inside Table and is not derivable from `dataSource`, so the row count
|
|
17
|
+
* and the highlighted row's key are both read from the popup DOM.
|
|
18
|
+
*/
|
|
19
|
+
export default function useTableSelectKeyboard(_ref) {
|
|
20
|
+
var open = _ref.open,
|
|
21
|
+
disabled = _ref.disabled,
|
|
22
|
+
dataSource = _ref.dataSource,
|
|
23
|
+
rowKey = _ref.rowKey,
|
|
24
|
+
selectionType = _ref.selectionType,
|
|
25
|
+
selectedRowKeys = _ref.selectedRowKeys,
|
|
26
|
+
searchValue = _ref.searchValue,
|
|
27
|
+
onSelect = _ref.onSelect,
|
|
28
|
+
onClose = _ref.onClose;
|
|
29
|
+
var popupRef = useRef(null);
|
|
30
|
+
// 1-based index of the highlighted row (`tr[data-row-index]`), 0 = none.
|
|
31
|
+
var _useState = useState(0),
|
|
32
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
33
|
+
activeRow = _useState2[0],
|
|
34
|
+
setActiveRow = _useState2[1];
|
|
35
|
+
useEffect(function () {
|
|
36
|
+
setActiveRow(0);
|
|
37
|
+
}, [open, searchValue]);
|
|
38
|
+
var getRecordKey = function getRecordKey(item) {
|
|
39
|
+
return typeof rowKey === 'function' ? rowKey(item) : item[rowKey];
|
|
40
|
+
};
|
|
41
|
+
var getRowCount = function getRowCount() {
|
|
42
|
+
var _popupRef$current$que, _popupRef$current;
|
|
43
|
+
return (_popupRef$current$que = (_popupRef$current = popupRef.current) === null || _popupRef$current === void 0 ? void 0 : _popupRef$current.querySelectorAll('tr[data-row-index]').length) !== null && _popupRef$current$que !== void 0 ? _popupRef$current$que : 0;
|
|
44
|
+
};
|
|
45
|
+
useEffect(function () {
|
|
46
|
+
var _popupRef$current2;
|
|
47
|
+
if (!open || activeRow < 1) return;
|
|
48
|
+
var rowEl = (_popupRef$current2 = popupRef.current) === null || _popupRef$current2 === void 0 ? void 0 : _popupRef$current2.querySelector("tr[data-row-index=\"".concat(activeRow, "\"]"));
|
|
49
|
+
if (!rowEl) return;
|
|
50
|
+
// Manual scroll instead of scrollIntoView: the popup renders in a portal,
|
|
51
|
+
// and scrollIntoView would scroll the page as well as the popup.
|
|
52
|
+
var parent = rowEl.parentElement;
|
|
53
|
+
while (parent && parent !== popupRef.current) {
|
|
54
|
+
var _window$getComputedSt = window.getComputedStyle(parent),
|
|
55
|
+
overflowY = _window$getComputedSt.overflowY;
|
|
56
|
+
if (/(auto|scroll)/.test(overflowY) && parent.scrollHeight > parent.clientHeight) {
|
|
57
|
+
var parentRect = parent.getBoundingClientRect();
|
|
58
|
+
var rowRect = rowEl.getBoundingClientRect();
|
|
59
|
+
if (rowRect.bottom > parentRect.bottom) {
|
|
60
|
+
parent.scrollTop += rowRect.bottom - parentRect.bottom;
|
|
61
|
+
} else if (rowRect.top < parentRect.top) {
|
|
62
|
+
parent.scrollTop -= parentRect.top - rowRect.top;
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
parent = parent.parentElement;
|
|
67
|
+
}
|
|
68
|
+
}, [activeRow, open]);
|
|
69
|
+
var selectActiveRow = function selectActiveRow() {
|
|
70
|
+
var _popupRef$current3;
|
|
71
|
+
var rowEl = (_popupRef$current3 = popupRef.current) === null || _popupRef$current3 === void 0 ? void 0 : _popupRef$current3.querySelector("tr[data-row-index=\"".concat(activeRow, "\"]"));
|
|
72
|
+
var inputEl = rowEl === null || rowEl === void 0 ? void 0 : rowEl.querySelector('input[type="radio"],input[type="checkbox"]');
|
|
73
|
+
if (!inputEl || inputEl.disabled) return;
|
|
74
|
+
var record = dataSource.find(function (item) {
|
|
75
|
+
return String(getRecordKey(item)) === inputEl.value;
|
|
76
|
+
});
|
|
77
|
+
if (!record) return;
|
|
78
|
+
var key = getRecordKey(record);
|
|
79
|
+
if (selectionType === 'radio') {
|
|
80
|
+
// Same shape as the click path: arrays, normalized by the consumer.
|
|
81
|
+
onSelect([key], [record]);
|
|
82
|
+
onClose();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
var checked = selectedRowKeys.some(function (k) {
|
|
86
|
+
return String(k) === String(key);
|
|
87
|
+
});
|
|
88
|
+
var nextKeys = checked ? selectedRowKeys.filter(function (k) {
|
|
89
|
+
return String(k) !== String(key);
|
|
90
|
+
}) : [].concat(_toConsumableArray(selectedRowKeys), [key]);
|
|
91
|
+
var rows = dataSource.filter(function (item) {
|
|
92
|
+
return nextKeys.some(function (k) {
|
|
93
|
+
return String(getRecordKey(item)) === String(k);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
onSelect(nextKeys, rows);
|
|
97
|
+
};
|
|
98
|
+
var handleKeyDown = function handleKeyDown(event) {
|
|
99
|
+
if (!open || disabled) return;
|
|
100
|
+
switch (event.key) {
|
|
101
|
+
case 'ArrowDown':
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
setActiveRow(Math.min(activeRow + 1, getRowCount()));
|
|
104
|
+
break;
|
|
105
|
+
case 'ArrowUp':
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
setActiveRow(activeRow <= 1 ? getRowCount() : activeRow - 1);
|
|
108
|
+
break;
|
|
109
|
+
case ' ':
|
|
110
|
+
// With nothing highlighted, space keeps its native input behavior.
|
|
111
|
+
if (activeRow > 0) {
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
selectActiveRow();
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
case 'Escape':
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
// Stop the event from reaching outer layers (e.g. a Dialog's useEsc
|
|
119
|
+
// listening on document) so only the dropdown closes.
|
|
120
|
+
event.stopPropagation();
|
|
121
|
+
onClose();
|
|
122
|
+
break;
|
|
123
|
+
default:
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
popupRef: popupRef,
|
|
129
|
+
activeRow: activeRow,
|
|
130
|
+
handleKeyDown: handleKeyDown
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -9,7 +9,7 @@ type SelectedKeyType = string | number;
|
|
|
9
9
|
/**
|
|
10
10
|
* Data item type
|
|
11
11
|
*/
|
|
12
|
-
type
|
|
12
|
+
export type TableSelectDataType = {
|
|
13
13
|
[propName: string]: any;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
@@ -40,7 +40,7 @@ export interface InternalTableProps {
|
|
|
40
40
|
/**
|
|
41
41
|
* Data source
|
|
42
42
|
*/
|
|
43
|
-
dataSource: Array<
|
|
43
|
+
dataSource: Array<TableSelectDataType>;
|
|
44
44
|
/**
|
|
45
45
|
* Custom class name
|
|
46
46
|
*/
|
|
@@ -65,6 +65,11 @@ export interface InternalTableProps {
|
|
|
65
65
|
* Whether popup is visible (for focus trap)
|
|
66
66
|
*/
|
|
67
67
|
visible?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Ref to the popup root element, used by TableSelect for keyboard navigation
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
popupRef?: React.RefObject<HTMLDivElement | null>;
|
|
68
73
|
}
|
|
69
74
|
/**
|
|
70
75
|
* TableSelect component Props interface
|
|
@@ -77,7 +82,7 @@ export interface TableSelectProps extends Omit<InternalTableProps, 'value' | 'on
|
|
|
77
82
|
/**
|
|
78
83
|
* Data source
|
|
79
84
|
*/
|
|
80
|
-
dataSource: Array<
|
|
85
|
+
dataSource: Array<TableSelectDataType>;
|
|
81
86
|
/**
|
|
82
87
|
* Single or multiple selection
|
|
83
88
|
* @default: 'radio'
|
|
@@ -161,7 +166,7 @@ export interface TableSelectProps extends Omit<InternalTableProps, 'value' | 'on
|
|
|
161
166
|
* Option label property (text field for displaying labels)
|
|
162
167
|
* @default 'name'
|
|
163
168
|
*/
|
|
164
|
-
optionLabelProp?: string | ((option:
|
|
169
|
+
optionLabelProp?: string | ((option: TableSelectDataType) => string);
|
|
165
170
|
/**
|
|
166
171
|
* Selection change callback
|
|
167
172
|
* @param keys Selected keys
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
-
var _excluded = ["prefixCls", "type", "value", "columns", "dataSource", "rowKey", "isShowFilter", "rowSelection", "visible"];
|
|
2
|
+
var _excluded = ["prefixCls", "type", "value", "columns", "dataSource", "rowKey", "isShowFilter", "rowSelection", "visible", "popupRef"];
|
|
3
3
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
4
4
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
5
5
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -32,6 +32,7 @@ var InternalTable = function InternalTable(props) {
|
|
|
32
32
|
_props$rowSelection = props.rowSelection,
|
|
33
33
|
rowSelection = _props$rowSelection === void 0 ? {} : _props$rowSelection,
|
|
34
34
|
visible = props.visible,
|
|
35
|
+
externalPopupRef = props.popupRef,
|
|
35
36
|
rest = _objectWithoutProperties(props, _excluded);
|
|
36
37
|
var _useState = useState([]),
|
|
37
38
|
_useState2 = _slicedToArray(_useState, 2),
|
|
@@ -77,7 +78,10 @@ var InternalTable = function InternalTable(props) {
|
|
|
77
78
|
return /*#__PURE__*/React.createElement("div", {
|
|
78
79
|
className: "".concat(prefixCls, "-popup"),
|
|
79
80
|
tabIndex: 0,
|
|
80
|
-
ref:
|
|
81
|
+
ref: function ref(node) {
|
|
82
|
+
popupRef.current = node;
|
|
83
|
+
if (externalPopupRef) externalPopupRef.current = node;
|
|
84
|
+
}
|
|
81
85
|
}, renderRadio(), /*#__PURE__*/React.createElement(Table, _extends({}, rest, {
|
|
82
86
|
rowKey: rowKey,
|
|
83
87
|
dataSource: internalDataSource,
|
|
@@ -6,16 +6,8 @@
|
|
|
6
6
|
margin: 0;
|
|
7
7
|
padding: 12px 0;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.rb-table-select {
|
|
16
|
-
margin-bottom: 0;
|
|
17
|
-
|
|
18
|
-
.rb-table-footer-operate {
|
|
19
|
-
padding: 0 12px;
|
|
9
|
+
// Keyboard-navigated row (TableSelect arrow keys)
|
|
10
|
+
.yee-table-highlight-row {
|
|
11
|
+
background-color: var(--yee-table-tbody-tr-hover-bg-color);
|
|
20
12
|
}
|
|
21
13
|
}
|
|
@@ -27,10 +27,14 @@ import Trigger from "../Trigger";
|
|
|
27
27
|
import mergeContextToProps from "../utils/mergeContextToProps";
|
|
28
28
|
import omit from "../utils/omit";
|
|
29
29
|
import pick from "../utils/pick";
|
|
30
|
+
import useTableSelectKeyboard from "./hooks/useTableSelectKeyboard";
|
|
30
31
|
import InternalTable from "./internal-table";
|
|
31
32
|
import "./style/index.less";
|
|
32
33
|
var handleState = function handleState(value) {
|
|
33
|
-
|
|
34
|
+
// '' is the empty-value convention for radio; it must not become a key.
|
|
35
|
+
if (value === '') {
|
|
36
|
+
return [];
|
|
37
|
+
} else if (typeof value === 'string' || typeof value === 'number') {
|
|
34
38
|
return [value];
|
|
35
39
|
} else if (Array.isArray(value)) {
|
|
36
40
|
return value;
|
|
@@ -140,8 +144,28 @@ var TableSelect = function TableSelect(baseprops) {
|
|
|
140
144
|
var renderKeys = keys.length === 0 ? selectionType === 'checkbox' ? [] : '' : keys;
|
|
141
145
|
onChange === null || onChange === void 0 || onChange(renderKeys, undefined);
|
|
142
146
|
};
|
|
147
|
+
var _useTableSelectKeyboa = useTableSelectKeyboard({
|
|
148
|
+
open: open,
|
|
149
|
+
disabled: disabled,
|
|
150
|
+
dataSource: dataSource,
|
|
151
|
+
rowKey: rowKey,
|
|
152
|
+
selectionType: selectionType,
|
|
153
|
+
selectedRowKeys: mergedValue,
|
|
154
|
+
searchValue: searchValue,
|
|
155
|
+
onSelect: onSelectChange,
|
|
156
|
+
onClose: function onClose() {
|
|
157
|
+
return onVisibleChange(false);
|
|
158
|
+
}
|
|
159
|
+
}),
|
|
160
|
+
popupRef = _useTableSelectKeyboa.popupRef,
|
|
161
|
+
activeRow = _useTableSelectKeyboa.activeRow,
|
|
162
|
+
handleSelectorKeyDown = _useTableSelectKeyboa.handleKeyDown;
|
|
163
|
+
var userHighlight = rest.highlight;
|
|
143
164
|
var tableProps = omit(_objectSpread(_objectSpread({}, rest), {}, {
|
|
144
165
|
prefixCls: prefixCls,
|
|
166
|
+
// Keyboard navigation reuses the row highlight; it takes precedence over
|
|
167
|
+
// a user-supplied index list while active.
|
|
168
|
+
highlight: activeRow > 0 ? [activeRow].concat(_toConsumableArray(Array.isArray(userHighlight) ? userHighlight : [])) : userHighlight,
|
|
145
169
|
rowSelection: _objectSpread(_objectSpread({}, props.rowSelection), {}, {
|
|
146
170
|
onChange: onSelectChange,
|
|
147
171
|
selectedRowKeys: mergedValue
|
|
@@ -158,8 +182,15 @@ var TableSelect = function TableSelect(baseprops) {
|
|
|
158
182
|
selectedKeys: mergedValue,
|
|
159
183
|
onSearch: handleSearch,
|
|
160
184
|
onRemove: onTagRemove,
|
|
185
|
+
onClear: function onClear() {
|
|
186
|
+
setMergedValue([]);
|
|
187
|
+
onChange === null || onChange === void 0 || onChange(selectionType === 'radio' ? '' : [], undefined);
|
|
188
|
+
},
|
|
189
|
+
onKeyDown: handleSelectorKeyDown,
|
|
161
190
|
onOpenChange: function onOpenChange(open) {
|
|
162
|
-
if (
|
|
191
|
+
if (open) {
|
|
192
|
+
onVisibleChange(true);
|
|
193
|
+
} else {
|
|
163
194
|
clearSearchValue();
|
|
164
195
|
}
|
|
165
196
|
},
|
|
@@ -171,11 +202,13 @@ var TableSelect = function TableSelect(baseprops) {
|
|
|
171
202
|
var renderPopup = function renderPopup() {
|
|
172
203
|
return /*#__PURE__*/React.createElement(InternalTable, _extends({}, tableProps, {
|
|
173
204
|
value: value,
|
|
174
|
-
rowKey: rowKey
|
|
205
|
+
rowKey: rowKey,
|
|
206
|
+
popupRef: popupRef
|
|
175
207
|
}));
|
|
176
208
|
};
|
|
177
209
|
return /*#__PURE__*/React.createElement(Trigger, _extends({}, rest, {
|
|
178
210
|
trigger: "click",
|
|
211
|
+
open: open,
|
|
179
212
|
popupClassName: "".concat(prefixCls, "-popup"),
|
|
180
213
|
popup: renderPopup(),
|
|
181
214
|
placement: placement,
|
package/dist/esm/style/color.css
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
--yee-color-text: #39364e;
|
|
30
30
|
--yee-color-text-secondary: #696969;
|
|
31
31
|
--yee-color-text-description: #7c7c7c;
|
|
32
|
-
--yee-color-text-disabled: #
|
|
32
|
+
--yee-color-text-disabled: #b8b8b8;
|
|
33
33
|
--yee-color-text-highlight: #f58220;
|
|
34
34
|
--yee-color-text-auxiliary: #d1d1d1;
|
|
35
35
|
--yee-color-split: #e7e7e7;
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
--yee-color-border-hover: #75b9f0;
|
|
38
38
|
--yee-color-border-focus: #75b9f0;
|
|
39
39
|
--yee-color-bg-highlight: rgba(245, 130, 32, 16%);
|
|
40
|
-
--yee-color-bg-disabled: #
|
|
40
|
+
--yee-color-bg-disabled: #f5f5f5;
|
|
41
41
|
--yee-color-bg-head: #f8f8f8;
|
|
42
42
|
--yee-color-bg-rail: #f5f5f5;
|
|
43
43
|
--yee-color-bg-fill: #ededed;
|
|
@@ -493,7 +493,7 @@
|
|
|
493
493
|
--yee-checkbox-checked-after-border-color: #fff;
|
|
494
494
|
--yee-checkbox-disabled-unchecked-bg-color: var(--yee-color-bg-disabled);
|
|
495
495
|
--yee-checkbox-disabled-checked-bg-color: var(--yee-color-bg-disabled);
|
|
496
|
-
--yee-checkbox-disabled-checked-border-color: var(--yee-color-
|
|
496
|
+
--yee-checkbox-disabled-checked-border-color: var(--yee-color-text-disabled);
|
|
497
497
|
--yee-checkbox-disabled-checked-after-border-color: var(
|
|
498
498
|
--yee-color-text-disabled
|
|
499
499
|
);
|
|
@@ -1223,7 +1223,7 @@
|
|
|
1223
1223
|
--yee-border-color-hover-focus: var(--yee-color-border-focus);
|
|
1224
1224
|
--yee-placeholder-color: var(--yee-color-placeholder);
|
|
1225
1225
|
|
|
1226
|
-
|
|
1226
|
+
/* deprecated:2026-09-11 hover/focus 拆分为 --yee-color-border-hover / --yee-color-border-focus */
|
|
1227
1227
|
--yee-color-border-hover-focus: var(--yee-color-border-focus);
|
|
1228
1228
|
/* deprecated:2026-09-11 更名 --yee-input-focus-border-color */
|
|
1229
1229
|
--yee-input-content-focus-border-color: var(--yee-input-focus-border-color);
|
|
@@ -1339,5 +1339,5 @@
|
|
|
1339
1339
|
--yee-timepicker-bg-color: var(--yee-time-picker-bg-color);
|
|
1340
1340
|
--yee-treeselect-dropdown-bg-color: var(--yee-tree-select-dropdown-bg-color);
|
|
1341
1341
|
|
|
1342
|
-
|
|
1342
|
+
/* deprecated-aliases:end */
|
|
1343
1343
|
}
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
/* ================= 背景 ================= */
|
|
80
80
|
--yee-color-bg-layout: #f1f2f4;
|
|
81
81
|
--yee-color-bg-head: #fff;
|
|
82
|
-
--yee-color-bg-disabled: #
|
|
82
|
+
--yee-color-bg-disabled: #f5f5f5;
|
|
83
83
|
/* 衍生:规范 --hover(极浅悬浮底) */
|
|
84
84
|
--yee-color-bg-hover: rgba(109, 93, 252, 3.5%);
|
|
85
85
|
|
package/dist/esm/style/size.css
CHANGED
|
@@ -587,7 +587,7 @@
|
|
|
587
587
|
--yee-select-popup-max-height: 200px;
|
|
588
588
|
|
|
589
589
|
/* --Selector-- */
|
|
590
|
-
--yee-selector-padding:
|
|
590
|
+
--yee-selector-padding: 3px 6px;
|
|
591
591
|
--yee-selector-border-width: 1px;
|
|
592
592
|
--yee-selector-border-radius: 4px;
|
|
593
593
|
--yee-selector-height: var(--yee-input-height);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @rainbow-oh/yee-c CSS Variables
|
|
3
3
|
* Auto-generated, do not edit manually
|
|
4
|
-
* Generated on 2026-10-
|
|
4
|
+
* Generated on 2026-10-15T09:51:26.325Z
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/* ========== color.blue.css ========== */
|
|
@@ -3846,7 +3846,7 @@
|
|
|
3846
3846
|
/* ================= 背景 ================= */
|
|
3847
3847
|
--yee-color-bg-layout: #f1f2f4;
|
|
3848
3848
|
--yee-color-bg-head: #fff;
|
|
3849
|
-
--yee-color-bg-disabled: #
|
|
3849
|
+
--yee-color-bg-disabled: #f5f5f5;
|
|
3850
3850
|
/* 衍生:规范 --hover(极浅悬浮底) */
|
|
3851
3851
|
--yee-color-bg-hover: rgba(109, 93, 252, 3.5%);
|
|
3852
3852
|
|