@rainbow-oh/yee-c 0.4.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/cjs/Dialog/demo/basic.js +1 -1
  2. package/dist/cjs/Dialog/dialog.js +1 -1
  3. package/dist/cjs/Field/demo/validation.js +23 -3
  4. package/dist/cjs/Field/field.js +1 -1
  5. package/dist/cjs/Form/Field.js +1 -4
  6. package/dist/cjs/Form/Form.js +1 -1
  7. package/dist/cjs/Form/Group.js +36 -14
  8. package/dist/cjs/Form/List.js +23 -3
  9. package/dist/cjs/Form/demo/async-validate.d.ts +3 -0
  10. package/dist/cjs/Form/demo/async-validate.js +108 -0
  11. package/dist/cjs/Form/demo/virtual.js +1 -1
  12. package/dist/cjs/Form/form-store.d.ts +4 -4
  13. package/dist/cjs/Form/form-store.js +55 -25
  14. package/dist/cjs/Form/interface.d.ts +10 -7
  15. package/dist/cjs/Form/utils/validate.d.ts +23 -2
  16. package/dist/cjs/Form/utils/validate.js +59 -10
  17. package/dist/cjs/Select/demo/basic.js +1 -1
  18. package/dist/cjs/Select/demo/virtual.d.ts +3 -0
  19. package/dist/cjs/Select/demo/virtual.js +55 -0
  20. package/dist/cjs/Select/hooks/useSelectKeyboard.d.ts +7 -1
  21. package/dist/cjs/Select/hooks/useSelectKeyboard.js +16 -6
  22. package/dist/cjs/Select/interface.d.ts +44 -0
  23. package/dist/cjs/Select/option.js +3 -2
  24. package/dist/cjs/Select/options.js +115 -15
  25. package/dist/cjs/Select/select.js +20 -4
  26. package/dist/cjs/Select/style/index.less +17 -0
  27. package/dist/cjs/Table/style/index.less +19 -0
  28. package/dist/cjs/hooks/index.d.ts +2 -1
  29. package/dist/cjs/hooks/index.js +3 -1
  30. package/dist/cjs/hooks/useVirtualList.d.ts +71 -0
  31. package/dist/cjs/hooks/useVirtualList.js +117 -0
  32. package/dist/cjs/style/themes.css +1 -1
  33. package/dist/cjs/style/variables.css +1 -1
  34. package/dist/cjs/version.d.ts +1 -1
  35. package/dist/cjs/version.js +1 -1
  36. package/dist/esm/Dialog/demo/basic.js +1 -1
  37. package/dist/esm/Dialog/dialog.js +1 -1
  38. package/dist/esm/Field/demo/validation.js +30 -9
  39. package/dist/esm/Field/field.js +2 -1
  40. package/dist/esm/Form/Field.js +3 -4
  41. package/dist/esm/Form/Form.js +1 -1
  42. package/dist/esm/Form/Group.js +142 -53
  43. package/dist/esm/Form/List.js +61 -42
  44. package/dist/esm/Form/demo/async-validate.d.ts +3 -0
  45. package/dist/esm/Form/demo/async-validate.js +95 -0
  46. package/dist/esm/Form/demo/virtual.js +1 -1
  47. package/dist/esm/Form/form-store.d.ts +4 -4
  48. package/dist/esm/Form/form-store.js +187 -93
  49. package/dist/esm/Form/interface.d.ts +10 -7
  50. package/dist/esm/Form/utils/validate.d.ts +23 -2
  51. package/dist/esm/Form/utils/validate.js +122 -17
  52. package/dist/esm/Select/demo/basic.js +1 -1
  53. package/dist/esm/Select/demo/virtual.d.ts +3 -0
  54. package/dist/esm/Select/demo/virtual.js +38 -0
  55. package/dist/esm/Select/hooks/useSelectKeyboard.d.ts +7 -1
  56. package/dist/esm/Select/hooks/useSelectKeyboard.js +25 -9
  57. package/dist/esm/Select/interface.d.ts +44 -0
  58. package/dist/esm/Select/option.js +4 -2
  59. package/dist/esm/Select/options.js +132 -13
  60. package/dist/esm/Select/select.js +19 -4
  61. package/dist/esm/Select/style/index.less +17 -0
  62. package/dist/esm/Table/style/index.less +19 -0
  63. package/dist/esm/hooks/index.d.ts +2 -1
  64. package/dist/esm/hooks/index.js +2 -1
  65. package/dist/esm/hooks/useVirtualList.d.ts +71 -0
  66. package/dist/esm/hooks/useVirtualList.js +129 -0
  67. package/dist/esm/style/themes.css +1 -1
  68. package/dist/esm/style/variables.css +1 -1
  69. package/dist/esm/version.d.ts +1 -1
  70. package/dist/esm/version.js +1 -1
  71. package/dist/umd/yee-c.min.css +1 -1
  72. package/dist/umd/yee-c.min.js +1 -1
  73. package/package.json +1 -1
  74. package/src/Dialog/demo/basic.tsx +1 -1
  75. package/src/Dialog/dialog.tsx +1 -1
  76. package/src/Field/demo/validation.tsx +2 -2
  77. package/src/Field/field.tsx +2 -1
  78. package/src/Field/index.en-US.md +1 -1
  79. package/src/Field/index.zh-CN.md +1 -1
  80. package/src/Form/Field.tsx +3 -4
  81. package/src/Form/Form.tsx +1 -1
  82. package/src/Form/Group.tsx +15 -12
  83. package/src/Form/List.tsx +3 -3
  84. package/src/Form/demo/async-validate.tsx +71 -0
  85. package/src/Form/demo/virtual.tsx +1 -1
  86. package/src/Form/form-store.ts +37 -21
  87. package/src/Form/index.en-US.md +6 -5
  88. package/src/Form/index.zh-CN.md +6 -5
  89. package/src/Form/interface.ts +13 -7
  90. package/src/Form/utils/validate.ts +65 -13
  91. package/src/Select/demo/basic.tsx +1 -1
  92. package/src/Select/demo/virtual.tsx +25 -0
  93. package/src/Select/hooks/useSelectKeyboard.ts +30 -6
  94. package/src/Select/index.en-US.md +4 -0
  95. package/src/Select/index.zh-CN.md +4 -0
  96. package/src/Select/interface.ts +48 -2
  97. package/src/Select/option.tsx +2 -1
  98. package/src/Select/options.tsx +139 -8
  99. package/src/Select/select.tsx +23 -1
  100. package/src/Select/style/index.less +17 -0
  101. package/src/Table/style/index.less +19 -0
  102. package/src/hooks/index.ts +2 -0
  103. package/src/hooks/useVirtualList.ts +169 -0
  104. package/src/version.ts +1 -1
@@ -15,11 +15,32 @@ var __copyProps = (to, from, except, desc) => {
15
15
  return to;
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var __async = (__this, __arguments, generator) => {
19
+ return new Promise((resolve, reject) => {
20
+ var fulfilled = (value) => {
21
+ try {
22
+ step(generator.next(value));
23
+ } catch (e) {
24
+ reject(e);
25
+ }
26
+ };
27
+ var rejected = (value) => {
28
+ try {
29
+ step(generator.throw(value));
30
+ } catch (e) {
31
+ reject(e);
32
+ }
33
+ };
34
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
35
+ step((generator = generator.apply(__this, __arguments)).next());
36
+ });
37
+ };
18
38
 
19
39
  // src/Form/utils/validate.ts
20
40
  var validate_exports = {};
21
41
  __export(validate_exports, {
22
- default: () => validate_default
42
+ default: () => validate_default,
43
+ runValidator: () => runValidator
23
44
  });
24
45
  module.exports = __toCommonJS(validate_exports);
25
46
  function isEmpty(v) {
@@ -80,8 +101,8 @@ function verifyRuleOfRegexp(regexp, value) {
80
101
  return true;
81
102
  }
82
103
  }
83
- function verifyMain(rule, value) {
84
- const { min, max, minLength, maxLength, regexp, validator } = rule;
104
+ function verifySyncRules(rule, value) {
105
+ const { min, max, minLength, maxLength, regexp } = rule;
85
106
  if (typeof min !== "undefined" && !verifyRuleOfMin(min, value)) {
86
107
  return false;
87
108
  }
@@ -97,15 +118,43 @@ function verifyMain(rule, value) {
97
118
  if (regexp instanceof RegExp && !verifyRuleOfRegexp(regexp, value)) {
98
119
  return false;
99
120
  }
100
- if (typeof validator === "function" && !validator(value)) {
101
- return false;
102
- }
103
121
  return true;
104
122
  }
123
+ function runValidator(validator, value) {
124
+ return __async(this, null, function* () {
125
+ try {
126
+ const res = validator(value);
127
+ if (res instanceof Promise) {
128
+ const resolved = yield res;
129
+ if (resolved === false) {
130
+ return { passed: false };
131
+ }
132
+ return { passed: true };
133
+ }
134
+ if (res === false) {
135
+ return { passed: false };
136
+ }
137
+ return { passed: true };
138
+ } catch (e) {
139
+ return {
140
+ passed: false,
141
+ message: e instanceof Error ? e.message : String(e)
142
+ };
143
+ }
144
+ });
145
+ }
105
146
  function validate(rule, value) {
106
- if (rule.required && isEmpty(value)) {
107
- return false;
108
- }
109
- return verifyMain(rule, value);
147
+ return __async(this, null, function* () {
148
+ if (rule.required && isEmpty(value)) {
149
+ return { passed: false };
150
+ }
151
+ if (!verifySyncRules(rule, value)) {
152
+ return { passed: false };
153
+ }
154
+ if (typeof rule.validator === "function") {
155
+ return runValidator(rule.validator, value);
156
+ }
157
+ return { passed: true };
158
+ });
110
159
  }
111
160
  var validate_default = validate;
@@ -47,7 +47,7 @@ var options = [
47
47
  { label: "Peach", value: "peach" }
48
48
  ];
49
49
  var basic_default = () => {
50
- const [value, setValue] = (0, import_react.useState)("apple");
50
+ const [value, setValue] = (0, import_react.useState)("mango");
51
51
  return /* @__PURE__ */ import_react.default.createElement(
52
52
  import_yee_c.Select,
53
53
  {
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const _default: () => React.JSX.Element;
3
+ export default _default;
@@ -0,0 +1,55 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/Select/demo/virtual.tsx
30
+ var virtual_exports = {};
31
+ __export(virtual_exports, {
32
+ default: () => virtual_default
33
+ });
34
+ module.exports = __toCommonJS(virtual_exports);
35
+ var import_yee_c = require("../..");
36
+ var import_react = __toESM(require("react"));
37
+ var options = Array.from({ length: 5e3 }, (_, i) => ({
38
+ label: `Option ${i + 1}`,
39
+ value: i
40
+ }));
41
+ var virtual_default = () => {
42
+ const [value, setValue] = (0, import_react.useState)(100);
43
+ return /* @__PURE__ */ import_react.default.createElement(
44
+ import_yee_c.Select,
45
+ {
46
+ virtual: true,
47
+ searchable: true,
48
+ value,
49
+ onChange: (val) => setValue(val),
50
+ options,
51
+ style: { width: 200 },
52
+ placeholder: "Please select"
53
+ }
54
+ );
55
+ };
@@ -11,8 +11,14 @@ interface UseSelectKeyboardParams {
11
11
  onClose?: () => void;
12
12
  onOpenChange?: (open: boolean) => void;
13
13
  containerRef?: React.RefObject<HTMLElement>;
14
+ /**
15
+ * Virtual-mode scroll hook. When provided, keyboard navigation drives the
16
+ * virtual viewport through this callback instead of calling scrollIntoView
17
+ * (the focused option may not be in the DOM while virtualized).
18
+ */
19
+ scrollToIndex?: (index: number) => void;
14
20
  }
15
- export default function useSelectKeyboard({ options, open, selectedKeys, onSelect, onClose, onOpenChange, containerRef, }: UseSelectKeyboardParams): {
21
+ export default function useSelectKeyboard({ options, open, selectedKeys, onSelect, onClose, onOpenChange, containerRef, scrollToIndex, }: UseSelectKeyboardParams): {
16
22
  focusedKey: string | number;
17
23
  onKeyDown: (event: React.KeyboardEvent) => void;
18
24
  };
@@ -41,7 +41,8 @@ function useSelectKeyboard({
41
41
  onSelect,
42
42
  onClose,
43
43
  onOpenChange,
44
- containerRef
44
+ containerRef,
45
+ scrollToIndex
45
46
  }) {
46
47
  const [focusedKey, setFocusedKey] = (0, import_react.useState)("");
47
48
  const latestFocusedKey = (0, import_useLatest.default)(focusedKey);
@@ -69,6 +70,10 @@ function useSelectKeyboard({
69
70
  }
70
71
  };
71
72
  const scrollOptionIntoView = (index) => {
73
+ if (scrollToIndex) {
74
+ scrollToIndex(index);
75
+ return;
76
+ }
72
77
  const container = containerRef == null ? void 0 : containerRef.current;
73
78
  if (!container)
74
79
  return;
@@ -150,18 +155,23 @@ function useSelectKeyboard({
150
155
  };
151
156
  (0, import_react.useEffect)(() => {
152
157
  if (open) {
158
+ let focusedValue = "";
153
159
  if ((selectedKeys == null ? void 0 : selectedKeys.length) > 0) {
154
160
  const firstSelected = options == null ? void 0 : options.find(
155
161
  (opt) => opt.value === selectedKeys[0]
156
162
  );
157
163
  if (firstSelected && !firstSelected.disabled) {
158
- setFocusedKey(firstSelected.value);
159
- return;
164
+ focusedValue = firstSelected.value;
165
+ }
166
+ }
167
+ if (!focusedValue) {
168
+ const firstEnabled = options == null ? void 0 : options.find((opt) => !opt.disabled);
169
+ if (firstEnabled) {
170
+ focusedValue = firstEnabled.value;
160
171
  }
161
172
  }
162
- const firstEnabled = options == null ? void 0 : options.find((opt) => !opt.disabled);
163
- if (firstEnabled) {
164
- setFocusedKey(firstEnabled.value);
173
+ if (focusedValue) {
174
+ setFocusedKey(focusedValue);
165
175
  }
166
176
  } else {
167
177
  setFocusedKey("");
@@ -94,6 +94,26 @@ export interface SelectProps extends DataAttributeProps {
94
94
  * Callback when searching
95
95
  */
96
96
  onFilter?: (value: string, options: Array<Option>) => Array<Option>;
97
+ /**
98
+ * Enable virtual scrolling for the dropdown.
99
+ *
100
+ * When enabled, only the options inside the visible window are rendered
101
+ * (the DOM node count stays constant regardless of how many options there
102
+ * are). Recommended for large option sets (hundreds or thousands).
103
+ * @default false
104
+ */
105
+ virtual?: boolean;
106
+ /**
107
+ * Height of each option in pixels. Required to be a fixed value when
108
+ * `virtual` is enabled (the list assumes every option has exactly this height).
109
+ * @default 32
110
+ */
111
+ itemHeight?: number;
112
+ /**
113
+ * Max height of the dropdown popup in pixels.
114
+ * @default 200
115
+ */
116
+ listHeight?: number;
97
117
  }
98
118
  /**
99
119
  * Props for the internal Option component (renders a single dropdown option).
@@ -119,6 +139,11 @@ export interface OptionProps {
119
139
  * Test id forwarded to the option element
120
140
  */
121
141
  dataTestId?: string;
142
+ /**
143
+ * Inline style forwarded to the option element.
144
+ * Used by virtual scrolling to position each option absolutely.
145
+ */
146
+ style?: React.CSSProperties;
122
147
  }
123
148
  /**
124
149
  * Context value shared between Options and each Option.
@@ -167,6 +192,25 @@ export interface OptionsProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
167
192
  * Whether multiple selection mode is active
168
193
  */
169
194
  multiple: boolean;
195
+ /**
196
+ * Whether virtual scrolling is enabled
197
+ */
198
+ virtual?: boolean;
199
+ /**
200
+ * Fixed option height in pixels (only meaningful when `virtual` is enabled)
201
+ */
202
+ itemHeight?: number;
203
+ /**
204
+ * Max popup height in pixels (only meaningful when `virtual` is enabled)
205
+ */
206
+ listHeight?: number;
207
+ /**
208
+ * Ref that receives the virtual list API (currently `scrollToIndex`),
209
+ * so the parent can wire keyboard navigation to the virtual viewport.
210
+ */
211
+ virtualApiRef?: React.MutableRefObject<{
212
+ scrollToIndex: (index: number) => void;
213
+ } | null>;
170
214
  /**
171
215
  * Callback when an option is selected
172
216
  */
@@ -37,7 +37,7 @@ var import_lucide_react = require("lucide-react");
37
37
  var import_react = __toESM(require("react"));
38
38
  var import_options = require("./options");
39
39
  var Option = (props) => {
40
- const { label, value, disabled, title, dataTestId } = props;
40
+ const { label, value, disabled, title, dataTestId, style } = props;
41
41
  const { prefixCls, selectedKeys, focusedKey, multiple, onSelect } = (0, import_react.useContext)(import_options.OptionsCtx);
42
42
  const handleClick = (e) => {
43
43
  if (!disabled) {
@@ -64,7 +64,8 @@ var Option = (props) => {
64
64
  role: "option",
65
65
  tabIndex: disabled ? void 0 : 0,
66
66
  title: htmlTitle,
67
- "data-testid": dataTestId
67
+ "data-testid": dataTestId,
68
+ style
68
69
  },
69
70
  /* @__PURE__ */ import_react.default.createElement("div", { className: `${prefixCls}-option-content` }, label),
70
71
  multiple && selected && /* @__PURE__ */ import_react.default.createElement("span", { className: `${prefixCls}-option-state` }, /* @__PURE__ */ import_react.default.createElement(import_lucide_react.Check, { size: 16 }))
@@ -64,6 +64,7 @@ __export(options_exports, {
64
64
  module.exports = __toCommonJS(options_exports);
65
65
  var import_clsx = __toESM(require("clsx"));
66
66
  var import_react = __toESM(require("react"));
67
+ var import_useVirtualList = __toESM(require("../hooks/useVirtualList"));
67
68
  var import_locale = require("../locale");
68
69
  var import_option = __toESM(require("./option"));
69
70
  var OptionsCtx = (0, import_react.createContext)(
@@ -82,6 +83,10 @@ var Options = (0, import_react.forwardRef)(
82
83
  focusedKey,
83
84
  dataTestId,
84
85
  multiple,
86
+ virtual,
87
+ itemHeight = 32,
88
+ listHeight = 200,
89
+ virtualApiRef,
85
90
  onSelect
86
91
  } = _a, rest = __objRest(_a, [
87
92
  "prefixCls",
@@ -92,30 +97,125 @@ var Options = (0, import_react.forwardRef)(
92
97
  "focusedKey",
93
98
  "dataTestId",
94
99
  "multiple",
100
+ "virtual",
101
+ "itemHeight",
102
+ "listHeight",
103
+ "virtualApiRef",
95
104
  "onSelect"
96
105
  ]);
97
- const componentRef = ref || (0, import_react.useRef)(null);
106
+ const rootRef = (0, import_react.useRef)(null);
107
+ (0, import_react.useImperativeHandle)(ref, () => rootRef.current, []);
108
+ const {
109
+ start,
110
+ end,
111
+ offsetY,
112
+ totalHeight,
113
+ viewportRef,
114
+ onScroll,
115
+ scrollToIndex
116
+ } = (0, import_useVirtualList.default)({
117
+ itemCount: options.length,
118
+ itemHeight
119
+ });
120
+ (0, import_react.useEffect)(() => {
121
+ if (!virtual || !virtualApiRef)
122
+ return;
123
+ virtualApiRef.current = { scrollToIndex };
124
+ return () => {
125
+ if (virtualApiRef.current) {
126
+ virtualApiRef.current = null;
127
+ }
128
+ };
129
+ }, [virtual, virtualApiRef, scrollToIndex]);
130
+ (0, import_react.useEffect)(() => {
131
+ if (virtual) {
132
+ scrollToIndex(0);
133
+ }
134
+ }, [options, virtual, scrollToIndex]);
135
+ (0, import_react.useEffect)(() => {
136
+ if (options.length === 0)
137
+ return;
138
+ if (focusedKey === "")
139
+ return;
140
+ const focusedIndex = options.findIndex((o) => o.value === focusedKey);
141
+ if (focusedIndex < 0)
142
+ return;
143
+ if (virtual) {
144
+ scrollToIndex(focusedIndex);
145
+ return;
146
+ }
147
+ const container = rootRef.current;
148
+ if (!container)
149
+ return;
150
+ const optionElements = container.querySelectorAll('[role="option"]');
151
+ const targetElement = optionElements[focusedIndex];
152
+ if (targetElement) {
153
+ targetElement.scrollIntoView({ block: "nearest" });
154
+ }
155
+ }, [focusedKey, virtual, options, scrollToIndex, rootRef]);
156
+ const isEmpty = options.length === 0;
157
+ const ctxValue = {
158
+ prefixCls,
159
+ selectedKeys,
160
+ focusedKey,
161
+ multiple,
162
+ onSelect
163
+ };
164
+ if (virtual && !isEmpty) {
165
+ const visibleOptions = options.slice(start, end);
166
+ return /* @__PURE__ */ import_react.default.createElement(
167
+ "div",
168
+ __spreadProps(__spreadValues({}, rest), {
169
+ className: (0, import_clsx.default)(
170
+ `${prefixCls}-popup`,
171
+ `${prefixCls}-popup-virtual`,
172
+ popupClassName
173
+ ),
174
+ style: popupStyle,
175
+ ref: rootRef,
176
+ tabIndex: -1
177
+ }),
178
+ /* @__PURE__ */ import_react.default.createElement(OptionsCtx.Provider, { value: ctxValue }, /* @__PURE__ */ import_react.default.createElement(
179
+ "div",
180
+ {
181
+ className: `${prefixCls}-popup-viewport`,
182
+ ref: viewportRef,
183
+ onScroll,
184
+ style: { maxHeight: listHeight, overflowY: "auto" }
185
+ },
186
+ /* @__PURE__ */ import_react.default.createElement("div", { style: { height: totalHeight, position: "relative" } }, visibleOptions.map((option, i) => /* @__PURE__ */ import_react.default.createElement(
187
+ import_option.default,
188
+ __spreadProps(__spreadValues({}, option), {
189
+ key: option.value,
190
+ dataTestId: `${dataTestId}-${start + i}`,
191
+ style: {
192
+ position: "absolute",
193
+ top: 0,
194
+ left: 0,
195
+ right: 0,
196
+ height: itemHeight,
197
+ transform: `translateY(${offsetY + i * itemHeight}px)`
198
+ }
199
+ })
200
+ )))
201
+ ))
202
+ );
203
+ }
98
204
  return /* @__PURE__ */ import_react.default.createElement(
99
205
  "div",
100
206
  __spreadProps(__spreadValues({}, rest), {
101
207
  className: (0, import_clsx.default)(`${prefixCls}-popup`, popupClassName),
102
208
  style: popupStyle,
103
- ref: componentRef,
209
+ ref: rootRef,
104
210
  tabIndex: -1
105
211
  }),
106
- options.length === 0 ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${prefixCls}-empty` }, select.noData) : /* @__PURE__ */ import_react.default.createElement(
107
- OptionsCtx.Provider,
108
- {
109
- value: { prefixCls, selectedKeys, focusedKey, multiple, onSelect }
110
- },
111
- options.map((option, index) => /* @__PURE__ */ import_react.default.createElement(
112
- import_option.default,
113
- __spreadProps(__spreadValues({}, option), {
114
- key: option.value,
115
- dataTestId: `${dataTestId}-${index}`
116
- })
117
- ))
118
- )
212
+ isEmpty ? /* @__PURE__ */ import_react.default.createElement("div", { className: `${prefixCls}-empty` }, select.noData) : /* @__PURE__ */ import_react.default.createElement(OptionsCtx.Provider, { value: ctxValue }, options.map((option, index) => /* @__PURE__ */ import_react.default.createElement(
213
+ import_option.default,
214
+ __spreadProps(__spreadValues({}, option), {
215
+ key: option.value,
216
+ dataTestId: `${dataTestId}-${index}`
217
+ })
218
+ )))
119
219
  );
120
220
  }
121
221
  );
@@ -83,7 +83,10 @@ var Select = (baseprops) => {
83
83
  optionFilterProp = "label",
84
84
  disabled,
85
85
  onChange,
86
- onFilter
86
+ onFilter,
87
+ virtual,
88
+ itemHeight,
89
+ listHeight
87
90
  } = _a, rest = __objRest(_a, [
88
91
  "prefixCls",
89
92
  "options",
@@ -94,7 +97,10 @@ var Select = (baseprops) => {
94
97
  "optionFilterProp",
95
98
  "disabled",
96
99
  "onChange",
97
- "onFilter"
100
+ "onFilter",
101
+ "virtual",
102
+ "itemHeight",
103
+ "listHeight"
98
104
  ]);
99
105
  const single = mode !== "multiple" && mode !== "tags" ? true : false;
100
106
  const handleState = (value2) => {
@@ -114,6 +120,11 @@ var Select = (baseprops) => {
114
120
  const [searchValue, setSearchValue] = (0, import_react.useState)("");
115
121
  const [open, setOpen] = (0, import_react.useState)(false);
116
122
  const popupRef = (0, import_react.useRef)(null);
123
+ const virtualApiRef = (0, import_react.useRef)(null);
124
+ const handleVirtualScrollToIndex = (0, import_react.useCallback)((index) => {
125
+ var _a2;
126
+ (_a2 = virtualApiRef.current) == null ? void 0 : _a2.scrollToIndex(index);
127
+ }, []);
117
128
  const getOptions = (keys) => {
118
129
  if (keys === "" || keys === null) {
119
130
  return void 0;
@@ -184,7 +195,8 @@ var Select = (baseprops) => {
184
195
  onSelect: handleSelect,
185
196
  onClose: () => setOpen(false),
186
197
  onOpenChange: handleOpenChange,
187
- containerRef: popupRef
198
+ containerRef: popupRef,
199
+ scrollToIndex: virtual ? handleVirtualScrollToIndex : void 0
188
200
  });
189
201
  const popup = /* @__PURE__ */ import_react.default.createElement(
190
202
  import_options.default,
@@ -196,7 +208,11 @@ var Select = (baseprops) => {
196
208
  selectedKeys: mergedValue,
197
209
  dataTestId: rest["data-testid"],
198
210
  onSelect: handleSelect,
199
- ref: popupRef
211
+ ref: popupRef,
212
+ virtual,
213
+ itemHeight,
214
+ listHeight,
215
+ virtualApiRef
200
216
  }
201
217
  );
202
218
  return /* @__PURE__ */ import_react.default.createElement(
@@ -8,6 +8,17 @@
8
8
  overflow: auto;
9
9
  }
10
10
 
11
+ // Virtual mode: the popup no longer scrolls itself; the inner viewport does.
12
+ // Without this override there would be two scrollbars.
13
+ &-popup-virtual {
14
+ max-height: none;
15
+ overflow: visible;
16
+ }
17
+
18
+ &-popup-viewport {
19
+ overflow-y: auto;
20
+ }
21
+
11
22
  &-option {
12
23
  display: flex;
13
24
  padding: var(--yee-select-option-padding);
@@ -37,6 +48,12 @@
37
48
  }
38
49
  }
39
50
 
51
+ // In virtual mode each option has a fixed inline height; center its content
52
+ // vertically so it stays aligned regardless of the inherited line-height.
53
+ &-popup-virtual &-option {
54
+ align-items: center;
55
+ }
56
+
40
57
  &-empty {
41
58
  padding: var(--yee-select-option-padding);
42
59
  }
@@ -23,13 +23,32 @@
23
23
  var(--yee-table-tbody-td-borderbottom-color);
24
24
  }
25
25
  }
26
+
27
+ @{pls}-cell {
28
+ &::before {
29
+ display: none;
30
+ }
31
+ }
26
32
  }
27
33
 
28
34
  &-thead {
29
35
  color: var(--yee-table-thead-color);
30
36
 
31
37
  @{pls}-cell {
38
+ position: relative;
32
39
  background-color: var(--yee-table-thead-bg-color);
40
+
41
+ &:not(:last-child):not(@{pls}-expand-col) {
42
+ &::before {
43
+ position: absolute;
44
+ content: '';
45
+ width: 1.5px;
46
+ height: 30%;
47
+ top: 35%;
48
+ right: 0;
49
+ background-color: var(--yee-table-head-cell-split-line-color, #eee);
50
+ }
51
+ }
33
52
  }
34
53
 
35
54
  &-cell {
@@ -16,4 +16,5 @@ import useMount from './useMount';
16
16
  import usePrevious from './usePrevious';
17
17
  import useUpdateEffect from './useUpdateEffect';
18
18
  import useVirtualForm from './useVirtualForm';
19
- export { useBreakpoint, useDebounceFunction, useDebounceValue, useDeepCompareEffect, useDeepCompareMemo, useDeepCompareMemoize, useDelayState, useEsc, useEvent, useIntersectionObserver, useKeyControl, useLatest, useLayoutEffect, useMergedState, useMount, usePrevious, useUpdateEffect, useVirtualForm, };
19
+ import useVirtualList from './useVirtualList';
20
+ export { useBreakpoint, useDebounceFunction, useDebounceValue, useDeepCompareEffect, useDeepCompareMemo, useDeepCompareMemoize, useDelayState, useEsc, useEvent, useIntersectionObserver, useKeyControl, useLatest, useLayoutEffect, useMergedState, useMount, usePrevious, useUpdateEffect, useVirtualForm, useVirtualList, };
@@ -46,7 +46,8 @@ __export(hooks_exports, {
46
46
  useMount: () => import_useMount.default,
47
47
  usePrevious: () => import_usePrevious.default,
48
48
  useUpdateEffect: () => import_useUpdateEffect.default,
49
- useVirtualForm: () => import_useVirtualForm.default
49
+ useVirtualForm: () => import_useVirtualForm.default,
50
+ useVirtualList: () => import_useVirtualList.default
50
51
  });
51
52
  module.exports = __toCommonJS(hooks_exports);
52
53
  var import_useBreakpoint = __toESM(require("./useBreakpoint"));
@@ -67,3 +68,4 @@ var import_useMount = __toESM(require("./useMount"));
67
68
  var import_usePrevious = __toESM(require("./usePrevious"));
68
69
  var import_useUpdateEffect = __toESM(require("./useUpdateEffect"));
69
70
  var import_useVirtualForm = __toESM(require("./useVirtualForm"));
71
+ var import_useVirtualList = __toESM(require("./useVirtualList"));