@rainbow-oh/yee-c 0.6.4 → 0.8.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 (145) hide show
  1. package/dist/cjs/Button/style/index.less +5 -4
  2. package/dist/cjs/Drawer/drawer.js +1 -1
  3. package/dist/cjs/Drawer/interface.d.ts +1 -1
  4. package/dist/cjs/Drawer/style/index.less +1 -0
  5. package/dist/cjs/Form/form-store.d.ts +2 -1
  6. package/dist/cjs/Form/form-store.js +32 -17
  7. package/dist/cjs/List/demo/virtual.d.ts +3 -0
  8. package/dist/cjs/List/demo/virtual.js +53 -0
  9. package/dist/cjs/List/hooks/useListKeyboard.d.ts +28 -0
  10. package/dist/cjs/List/hooks/useListKeyboard.js +188 -0
  11. package/dist/cjs/List/interface.d.ts +29 -2
  12. package/dist/cjs/List/list.js +141 -21
  13. package/dist/cjs/List/style/index.less +24 -0
  14. package/dist/cjs/Select/demo/columns.d.ts +3 -0
  15. package/dist/cjs/Select/demo/columns.js +62 -0
  16. package/dist/cjs/Select/hooks/useSelectKeyboard.d.ts +13 -1
  17. package/dist/cjs/Select/hooks/useSelectKeyboard.js +81 -10
  18. package/dist/cjs/Select/interface.d.ts +30 -3
  19. package/dist/cjs/Select/option.js +4 -3
  20. package/dist/cjs/Select/options.js +90 -8
  21. package/dist/cjs/Select/select.js +32 -8
  22. package/dist/cjs/Select/style/index.less +14 -0
  23. package/dist/cjs/Selector/interface.d.ts +4 -0
  24. package/dist/cjs/Selector/selector.js +5 -3
  25. package/dist/cjs/Table/hooks/useColumns.js +1 -1
  26. package/dist/cjs/Table/interface.d.ts +1 -1
  27. package/dist/cjs/Table/style/index.less +35 -11
  28. package/dist/cjs/Table/table.js +57 -7
  29. package/dist/cjs/Table/tbody/cell.js +1 -1
  30. package/dist/cjs/Table/util/header.d.ts +3 -1
  31. package/dist/cjs/Table/util/header.js +30 -3
  32. package/dist/cjs/Tree/demo/draggable.js +2 -0
  33. package/dist/cjs/Tree/interface.d.ts +46 -23
  34. package/dist/cjs/Tree/tree-node.d.ts +1 -1
  35. package/dist/cjs/Tree/tree-node.js +30 -23
  36. package/dist/cjs/Tree/tree.d.ts +13 -12
  37. package/dist/cjs/Tree/tree.js +452 -227
  38. package/dist/cjs/Tree/utils/tree-tools.d.ts +43 -10
  39. package/dist/cjs/Tree/utils/tree-tools.js +129 -91
  40. package/dist/cjs/locale/context.d.ts +5 -4
  41. package/dist/cjs/locale/context.js +15 -8
  42. package/dist/cjs/locale/interface.d.ts +20 -0
  43. package/dist/cjs/locale/util.d.ts +3 -3
  44. package/dist/cjs/style/color.css +3 -0
  45. package/dist/cjs/style/size.css +2 -1
  46. package/dist/cjs/style/themes.css +1 -1
  47. package/dist/cjs/style/variables.css +6 -2
  48. package/dist/cjs/utils/isEqual.js +5 -7
  49. package/dist/cjs/version.d.ts +1 -1
  50. package/dist/cjs/version.js +1 -1
  51. package/dist/esm/Button/style/index.less +5 -4
  52. package/dist/esm/Drawer/drawer.js +2 -1
  53. package/dist/esm/Drawer/interface.d.ts +1 -1
  54. package/dist/esm/Drawer/style/index.less +1 -0
  55. package/dist/esm/Form/form-store.d.ts +2 -1
  56. package/dist/esm/Form/form-store.js +40 -19
  57. package/dist/esm/List/demo/virtual.d.ts +3 -0
  58. package/dist/esm/List/demo/virtual.js +22 -0
  59. package/dist/esm/List/hooks/useListKeyboard.d.ts +28 -0
  60. package/dist/esm/List/hooks/useListKeyboard.js +173 -0
  61. package/dist/esm/List/interface.d.ts +29 -2
  62. package/dist/esm/List/list.js +171 -14
  63. package/dist/esm/List/style/index.less +24 -0
  64. package/dist/esm/Select/demo/columns.d.ts +3 -0
  65. package/dist/esm/Select/demo/columns.js +36 -0
  66. package/dist/esm/Select/hooks/useSelectKeyboard.d.ts +13 -1
  67. package/dist/esm/Select/hooks/useSelectKeyboard.js +91 -14
  68. package/dist/esm/Select/interface.d.ts +30 -3
  69. package/dist/esm/Select/option.js +6 -2
  70. package/dist/esm/Select/options.js +114 -32
  71. package/dist/esm/Select/select.js +40 -11
  72. package/dist/esm/Select/style/index.less +14 -0
  73. package/dist/esm/Selector/interface.d.ts +4 -0
  74. package/dist/esm/Selector/selector.js +10 -4
  75. package/dist/esm/Table/hooks/useColumns.js +1 -1
  76. package/dist/esm/Table/interface.d.ts +1 -1
  77. package/dist/esm/Table/style/index.less +35 -11
  78. package/dist/esm/Table/table.js +54 -2
  79. package/dist/esm/Table/tbody/cell.js +1 -1
  80. package/dist/esm/Table/util/header.d.ts +3 -1
  81. package/dist/esm/Table/util/header.js +30 -2
  82. package/dist/esm/Tree/demo/draggable.js +2 -0
  83. package/dist/esm/Tree/interface.d.ts +46 -23
  84. package/dist/esm/Tree/tree-node.d.ts +1 -1
  85. package/dist/esm/Tree/tree-node.js +26 -31
  86. package/dist/esm/Tree/tree.d.ts +13 -12
  87. package/dist/esm/Tree/tree.js +572 -163
  88. package/dist/esm/Tree/utils/tree-tools.d.ts +43 -10
  89. package/dist/esm/Tree/utils/tree-tools.js +219 -104
  90. package/dist/esm/locale/context.d.ts +5 -4
  91. package/dist/esm/locale/context.js +25 -9
  92. package/dist/esm/locale/interface.d.ts +20 -0
  93. package/dist/esm/locale/util.d.ts +3 -3
  94. package/dist/esm/style/color.css +3 -0
  95. package/dist/esm/style/size.css +2 -1
  96. package/dist/esm/style/themes.css +1 -1
  97. package/dist/esm/style/variables.css +6 -2
  98. package/dist/esm/utils/isEqual.js +5 -7
  99. package/dist/esm/version.d.ts +1 -1
  100. package/dist/esm/version.js +1 -1
  101. package/dist/umd/yee-c.min.css +4 -4
  102. package/dist/umd/yee-c.min.js +1 -1
  103. package/package.json +1 -1
  104. package/src/Button/style/index.less +5 -4
  105. package/src/Drawer/drawer.tsx +1 -1
  106. package/src/Drawer/interface.ts +1 -0
  107. package/src/Drawer/style/index.less +1 -0
  108. package/src/Form/form-store.ts +42 -15
  109. package/src/List/demo/virtual.tsx +20 -0
  110. package/src/List/hooks/useListKeyboard.ts +235 -0
  111. package/src/List/index.en-US.md +6 -0
  112. package/src/List/index.zh-CN.md +6 -0
  113. package/src/List/interface.ts +29 -2
  114. package/src/List/list.tsx +157 -19
  115. package/src/List/style/index.less +24 -0
  116. package/src/Select/demo/columns.tsx +35 -0
  117. package/src/Select/hooks/useSelectKeyboard.ts +112 -15
  118. package/src/Select/index.en-US.md +4 -0
  119. package/src/Select/index.zh-CN.md +4 -0
  120. package/src/Select/interface.ts +31 -4
  121. package/src/Select/option.tsx +9 -3
  122. package/src/Select/options.tsx +119 -26
  123. package/src/Select/select.tsx +41 -8
  124. package/src/Select/style/index.less +14 -0
  125. package/src/Selector/interface.ts +4 -0
  126. package/src/Selector/selector.tsx +8 -3
  127. package/src/Table/hooks/useColumns.ts +1 -1
  128. package/src/Table/interface.ts +1 -1
  129. package/src/Table/style/index.less +35 -11
  130. package/src/Table/table.tsx +60 -1
  131. package/src/Table/tbody/cell.tsx +1 -1
  132. package/src/Table/util/header.ts +48 -2
  133. package/src/Tree/demo/draggable.tsx +2 -0
  134. package/src/Tree/interface.ts +46 -23
  135. package/src/Tree/tree-node.tsx +26 -29
  136. package/src/Tree/tree.tsx +573 -274
  137. package/src/Tree/utils/tree-tools.ts +231 -125
  138. package/src/locale/_README.md +22 -13
  139. package/src/locale/context.tsx +33 -16
  140. package/src/locale/interface.ts +24 -0
  141. package/src/locale/util.ts +6 -6
  142. package/src/style/color.css +3 -0
  143. package/src/style/size.css +2 -1
  144. package/src/utils/isEqual.ts +5 -7
  145. package/src/version.ts +1 -1
@@ -171,7 +171,7 @@
171
171
  --m-btn-hover-color: var(--yee-primary-color-hover);
172
172
  --m-btn-active-color: var(--yee-primary-color-active);
173
173
  --m-btn-bg-color: var(--yee-btn-primary-bg-color);
174
- --m-btn-hover-bg-color: var(--yee-primary-color-hover);
174
+ --m-btn-hover-bg-color: var(--yee-primary-color-border);
175
175
  --m-btn-active-bg-color: var(--yee-primary-color-active);
176
176
  --m-btn-border-color: var(--yee-primary-color);
177
177
  --m-btn-border-hover-color: var(--yee-primary-color-hover);
@@ -186,7 +186,7 @@
186
186
  --m-btn-border-color: var(--yee-success-color);
187
187
  --m-btn-border-hover-color: var(--yee-success-color-hover);
188
188
  --m-btn-border-active-color: var(--yee-success-color-active);
189
- --m-btn-hover-bg-color: var(--yee-success-color-hover);
189
+ --m-btn-hover-bg-color: var(--yee-success-color-border);
190
190
  --m-btn-active-bg-color: var(--yee-success-color-active);
191
191
  --m-btn-active-shadow-color: var(--yee-success-color-active);
192
192
  }
@@ -198,7 +198,8 @@
198
198
  --m-btn-border-color: var(--yee-error-color);
199
199
  --m-btn-border-hover-color: var(--yee-error-color-hover);
200
200
  --m-btn-border-active-color: var(--yee-error-color-active);
201
- --m-btn-hover-bg-color: var(--yee-error-color-hover);
201
+ // --m-btn-hover-bg-color: var(--yee-error-color-hover);
202
+ --m-btn-hover-bg-color: var(--yee-error-color-border);
202
203
  --m-btn-active-bg-color: var(--yee-error-color-active);
203
204
  --m-btn-active-shadow-color: var(--yee-error-color-active);
204
205
  }
@@ -210,7 +211,7 @@
210
211
  --m-btn-border-color: var(--yee-warning-color);
211
212
  --m-btn-border-hover-color: var(--yee-warning-color-hover);
212
213
  --m-btn-border-active-color: var(--yee-warning-color-active);
213
- --m-btn-hover-bg-color: var(--yee-warning-color-hover);
214
+ --m-btn-hover-bg-color: var(--yee-warning-color-border);
214
215
  --m-btn-active-bg-color: var(--yee-warning-color-active);
215
216
  --m-btn-active-shadow-color: var(--yee-warning-color-active);
216
217
  }
@@ -228,7 +228,8 @@ var Drawer = function Drawer(baseprops) {
228
228
  className: clsx("".concat(prefixCls, "-header"), classNames === null || classNames === void 0 ? void 0 : classNames.header),
229
229
  style: styles === null || styles === void 0 ? void 0 : styles.header
230
230
  }, /*#__PURE__*/React.createElement("div", {
231
- className: "".concat(prefixCls, "-title")
231
+ className: clsx("".concat(prefixCls, "-title"), classNames === null || classNames === void 0 ? void 0 : classNames.title),
232
+ style: styles === null || styles === void 0 ? void 0 : styles.title
232
233
  }, title)) : null, /*#__PURE__*/React.createElement("div", {
233
234
  className: clsx("".concat(prefixCls, "-body"), classNames === null || classNames === void 0 ? void 0 : classNames.body),
234
235
  style: styles === null || styles === void 0 ? void 0 : styles.body
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import type { DataAttributeProps } from '../utils/types';
3
- export type SemanticDOM = 'mask' | 'wrapper' | 'close' | 'header' | 'content' | 'body' | 'footer';
3
+ export type SemanticDOM = 'mask' | 'wrapper' | 'close' | 'header' | 'title' | 'content' | 'body' | 'footer';
4
4
  export interface DrawerProps extends DataAttributeProps {
5
5
  /**
6
6
  * Custom prefix class name
@@ -38,6 +38,7 @@
38
38
  }
39
39
 
40
40
  &-title {
41
+ font-size: var(--yee-drawer-title-font-size);
41
42
  font-weight: var(--yee-drawer-title-font-weight);
42
43
  }
43
44
 
@@ -28,7 +28,8 @@ export declare class FormStore {
28
28
  clearFields: (name?: Name[]) => void;
29
29
  validateField: (name: Name, trigger?: TRIGGER) => Promise<ValidateMessage[]>;
30
30
  validateFields: (names?: string[], trigger?: TRIGGER) => Promise<ValidateMessage[]>;
31
- refreshField: (newStore?: Store) => void;
31
+ private getRelatedFieldNames;
32
+ refreshField: (newStore?: Store, relatedFieldNames?: Name[]) => void;
32
33
  subscribe: (namePath?: NamePath, callback?: () => void) => (() => void);
33
34
  private notifyWatchers;
34
35
  registerGroupEntity: (id: string, entity: GroupEntity) => (() => void);
@@ -34,6 +34,9 @@ function _move(array, from, to) {
34
34
  return result;
35
35
  }
36
36
  var GLOBAL_WATCH_KEY = '__ALL__';
37
+ var isRelatedNamePath = function isRelatedNamePath(first, second) {
38
+ return first === second || first.startsWith("".concat(second, ".")) || second.startsWith("".concat(first, "."));
39
+ };
37
40
  export var FormStore = /*#__PURE__*/function () {
38
41
  function FormStore() {
39
42
  var _this = this;
@@ -136,13 +139,15 @@ export var FormStore = /*#__PURE__*/function () {
136
139
  }
137
140
  });
138
141
  }
142
+ var changedKeys = Object.keys(newStore);
143
+ var relatedFieldNames = _this.getRelatedFieldNames(changedKeys);
139
144
 
140
145
  // Validate on onChange and onBlur (async — fire-and-forget so setFieldsValue
141
146
  // stays synchronous for its callers; results surface via onStoreChange).
142
147
  if (trigger === 'onChange' || trigger === 'onBlur' || trigger === 'onSubmit') {
143
- void _this.validateFields(Object.keys(newStore), trigger);
148
+ void _this.validateFields(relatedFieldNames, trigger);
144
149
  }
145
- _this.refreshField(newStore);
150
+ _this.refreshField(newStore, relatedFieldNames);
146
151
  });
147
152
  _defineProperty(this, "resetFields", function (name) {
148
153
  var _this$callbacks4, _this$callbacks4$onRe;
@@ -322,16 +327,22 @@ export var FormStore = /*#__PURE__*/function () {
322
327
  }
323
328
  }, _callee2);
324
329
  })));
325
- _defineProperty(this, "refreshField", function (newStore) {
330
+ _defineProperty(this, "getRelatedFieldNames", function (changedKeys) {
331
+ return Array.from(_this.fieldMap.keys()).filter(function (fieldName) {
332
+ return changedKeys.some(function (changedKey) {
333
+ return isRelatedNamePath(String(fieldName), changedKey);
334
+ });
335
+ });
336
+ });
337
+ _defineProperty(this, "refreshField", function (newStore, relatedFieldNames) {
326
338
  if (newStore) {
327
- var keys = Object.keys(newStore);
328
- keys.forEach(function (key) {
329
- var entity = _this.fieldMap.get(key);
330
- if (entity) {
331
- entity === null || entity === void 0 || entity.onStoreChange();
332
- }
333
- _this.notifyWatchers(key);
339
+ var changedKeys = Object.keys(newStore);
340
+ var fieldNames = relatedFieldNames !== null && relatedFieldNames !== void 0 ? relatedFieldNames : _this.getRelatedFieldNames(changedKeys);
341
+ fieldNames.forEach(function (fieldName) {
342
+ var _this$fieldMap$get;
343
+ (_this$fieldMap$get = _this.fieldMap.get(fieldName)) === null || _this$fieldMap$get === void 0 || _this$fieldMap$get.onStoreChange();
334
344
  });
345
+ _this.notifyWatchers(changedKeys);
335
346
  } else {
336
347
  _this.fieldEntities.forEach(function (entity) {
337
348
  entity === null || entity === void 0 || entity.onStoreChange();
@@ -347,18 +358,28 @@ export var FormStore = /*#__PURE__*/function () {
347
358
  }
348
359
  _this.watchers.get(key).add(callback);
349
360
  return function () {
350
- var _this$watchers$get;
351
- (_this$watchers$get = _this.watchers.get(key)) === null || _this$watchers$get === void 0 || _this$watchers$get.delete(callback);
361
+ var watchers = _this.watchers.get(key);
362
+ watchers === null || watchers === void 0 || watchers.delete(callback);
363
+ if ((watchers === null || watchers === void 0 ? void 0 : watchers.size) === 0) {
364
+ _this.watchers.delete(key);
365
+ }
352
366
  };
353
367
  });
354
- _defineProperty(this, "notifyWatchers", function (changedKey) {
355
- if (changedKey) {
356
- var _this$watchers$get2, _this$watchers$get3;
357
- (_this$watchers$get2 = _this.watchers.get(changedKey)) === null || _this$watchers$get2 === void 0 || _this$watchers$get2.forEach(function (cb) {
358
- return cb();
368
+ _defineProperty(this, "notifyWatchers", function (changedKeys) {
369
+ if (changedKeys) {
370
+ var keys = Array.isArray(changedKeys) ? changedKeys : [changedKeys];
371
+ var callbacks = new Set();
372
+ _this.watchers.forEach(function (watchers, watchedKey) {
373
+ if (watchedKey === GLOBAL_WATCH_KEY || keys.some(function (changedKey) {
374
+ return isRelatedNamePath(watchedKey, changedKey);
375
+ })) {
376
+ watchers.forEach(function (callback) {
377
+ return callbacks.add(callback);
378
+ });
379
+ }
359
380
  });
360
- (_this$watchers$get3 = _this.watchers.get(GLOBAL_WATCH_KEY)) === null || _this$watchers$get3 === void 0 || _this$watchers$get3.forEach(function (cb) {
361
- return cb();
381
+ callbacks.forEach(function (callback) {
382
+ return callback();
362
383
  });
363
384
  } else {
364
385
  _this.watchers.forEach(function (set) {
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const _default: () => React.JSX.Element;
3
+ export default _default;
@@ -0,0 +1,22 @@
1
+ import { List } from "../..";
2
+ import React from 'react';
3
+ var items = Array.from({
4
+ length: 10000
5
+ }, function (_, i) {
6
+ return {
7
+ key: String(i),
8
+ label: "List item ".concat(i + 1),
9
+ value: String(i)
10
+ };
11
+ });
12
+ export default (function () {
13
+ return /*#__PURE__*/React.createElement(List, {
14
+ virtual: true,
15
+ height: 300,
16
+ itemHeight: 32,
17
+ items: items,
18
+ onClick: function onClick(item) {
19
+ return console.log('Clicked:', item.label);
20
+ }
21
+ });
22
+ });
@@ -0,0 +1,28 @@
1
+ import type { ListItemProps } from '../interface';
2
+ interface UseListKeyboardParams {
3
+ items: Array<ListItemProps>;
4
+ /**
5
+ * Number of columns in the grid layout.
6
+ * Affects ArrowUp/Down (jump by columns) and ArrowLeft/Right behavior.
7
+ * @default 1
8
+ */
9
+ columns?: number;
10
+ /**
11
+ * Controlled focused key from the parent.
12
+ * When provided, the hook uses this value instead of internal state.
13
+ */
14
+ focusedKey?: string | number;
15
+ /**
16
+ * Callback when focused key changes.
17
+ */
18
+ onFocusChange?: (key: string | number) => void;
19
+ /**
20
+ * Callback when Enter is pressed on a focused item.
21
+ */
22
+ onClick?: (item: ListItemProps) => void;
23
+ }
24
+ export default function useListKeyboard({ items, columns, focusedKey: controlledFocusedKey, onFocusChange, onClick, }: UseListKeyboardParams): {
25
+ focusedKey: string | number;
26
+ onKeyDown: (event: React.KeyboardEvent) => void;
27
+ };
28
+ export {};
@@ -0,0 +1,173 @@
1
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
2
+ 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."); }
3
+ 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); }
4
+ 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; }
5
+ 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; } }
6
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
+ import { useCallback, useEffect, useState } from 'react';
8
+ export default function useListKeyboard(_ref) {
9
+ var items = _ref.items,
10
+ _ref$columns = _ref.columns,
11
+ columns = _ref$columns === void 0 ? 1 : _ref$columns,
12
+ controlledFocusedKey = _ref.focusedKey,
13
+ onFocusChange = _ref.onFocusChange,
14
+ onClick = _ref.onClick;
15
+ var _useState = useState(''),
16
+ _useState2 = _slicedToArray(_useState, 2),
17
+ internalFocusedKey = _useState2[0],
18
+ setInternalFocusedKey = _useState2[1];
19
+ var isControlled = controlledFocusedKey !== undefined;
20
+ var focusedKey = isControlled ? controlledFocusedKey : internalFocusedKey;
21
+ var setFocusedKey = useCallback(function (key) {
22
+ if (!isControlled) {
23
+ setInternalFocusedKey(key);
24
+ }
25
+ onFocusChange === null || onFocusChange === void 0 || onFocusChange(key);
26
+ }, [isControlled, onFocusChange]);
27
+
28
+ // Reset internal focused key if it no longer exists in items
29
+ useEffect(function () {
30
+ if (!isControlled && internalFocusedKey !== '' && !items.some(function (item) {
31
+ return item.key === internalFocusedKey;
32
+ })) {
33
+ setInternalFocusedKey('');
34
+ }
35
+ }, [items, isControlled, internalFocusedKey]);
36
+ var getFocusedIndex = function getFocusedIndex() {
37
+ if (focusedKey === '' || focusedKey === undefined) return -1;
38
+ return items.findIndex(function (item) {
39
+ return item.key === focusedKey;
40
+ });
41
+ };
42
+ var findNextEnabledIndex = function findNextEnabledIndex(startIndex, direction) {
43
+ var count = items.length;
44
+ if (count === 0) return -1;
45
+ var next = direction === 1 ? startIndex + 1 >= count ? 0 : startIndex + 1 : startIndex - 1 < 0 ? count - 1 : startIndex - 1;
46
+
47
+ // Guard against infinite loop if all items are disabled
48
+ var attempts = 0;
49
+ while (items[next].disabled && attempts < count) {
50
+ next = direction === 1 ? next + 1 >= count ? 0 : next + 1 : next - 1 < 0 ? count - 1 : next - 1;
51
+ attempts++;
52
+ }
53
+ return items[next].disabled ? -1 : next;
54
+ };
55
+ var handleArrowUp = function handleArrowUp() {
56
+ var focusedIndex = getFocusedIndex();
57
+ var nextIndex;
58
+ if (columns > 1) {
59
+ if (focusedIndex === -1) {
60
+ nextIndex = findNextEnabledIndex(items.length - 1, -1);
61
+ } else {
62
+ var target = focusedIndex - columns;
63
+ if (target >= 0) {
64
+ nextIndex = items[target].disabled ? findNextEnabledIndex(target, -1) : target;
65
+ } else {
66
+ var _items$wrapTarget;
67
+ // Wrap to last row, same column
68
+ var lastRowStart = Math.floor((items.length - 1) / columns) * columns;
69
+ var col = focusedIndex % columns;
70
+ var wrapTarget = Math.min(lastRowStart + col, items.length - 1);
71
+ nextIndex = (_items$wrapTarget = items[wrapTarget]) !== null && _items$wrapTarget !== void 0 && _items$wrapTarget.disabled ? findNextEnabledIndex(wrapTarget, -1) : wrapTarget;
72
+ }
73
+ }
74
+ } else {
75
+ if (focusedIndex === -1) {
76
+ nextIndex = findNextEnabledIndex(items.length - 1, -1);
77
+ } else {
78
+ nextIndex = findNextEnabledIndex(focusedIndex, -1);
79
+ }
80
+ }
81
+ if (nextIndex !== -1) {
82
+ setFocusedKey(items[nextIndex].key);
83
+ }
84
+ };
85
+ var handleArrowDown = function handleArrowDown() {
86
+ var focusedIndex = getFocusedIndex();
87
+ var nextIndex;
88
+ if (columns > 1) {
89
+ if (focusedIndex === -1) {
90
+ nextIndex = findNextEnabledIndex(-1, 1);
91
+ } else {
92
+ var target = focusedIndex + columns;
93
+ if (target < items.length) {
94
+ nextIndex = items[target].disabled ? findNextEnabledIndex(target, 1) : target;
95
+ } else {
96
+ var _items$wrapTarget2;
97
+ // Wrap to first row, same column
98
+ var col = focusedIndex % columns;
99
+ var wrapTarget = col;
100
+ nextIndex = (_items$wrapTarget2 = items[wrapTarget]) !== null && _items$wrapTarget2 !== void 0 && _items$wrapTarget2.disabled ? findNextEnabledIndex(wrapTarget, 1) : wrapTarget;
101
+ }
102
+ }
103
+ } else {
104
+ if (focusedIndex === -1) {
105
+ nextIndex = findNextEnabledIndex(-1, 1);
106
+ } else {
107
+ nextIndex = findNextEnabledIndex(focusedIndex, 1);
108
+ }
109
+ }
110
+ if (nextIndex !== -1) {
111
+ setFocusedKey(items[nextIndex].key);
112
+ }
113
+ };
114
+ var handleArrowLeft = function handleArrowLeft() {
115
+ var focusedIndex = getFocusedIndex();
116
+ if (focusedIndex <= 0) return;
117
+ var nextIndex = findNextEnabledIndex(focusedIndex, -1);
118
+ if (nextIndex !== -1) {
119
+ setFocusedKey(items[nextIndex].key);
120
+ }
121
+ };
122
+ var handleArrowRight = function handleArrowRight() {
123
+ var focusedIndex = getFocusedIndex();
124
+ if (focusedIndex >= items.length - 1 && focusedIndex !== -1) return;
125
+ var nextIndex = findNextEnabledIndex(focusedIndex === -1 ? -1 : focusedIndex, 1);
126
+ if (nextIndex !== -1) {
127
+ setFocusedKey(items[nextIndex].key);
128
+ }
129
+ };
130
+ var handleEnter = function handleEnter() {
131
+ if (focusedKey === '' || focusedKey === undefined) return;
132
+ var item = items.find(function (i) {
133
+ return i.key === focusedKey;
134
+ });
135
+ if (item && !item.disabled) {
136
+ onClick === null || onClick === void 0 || onClick(item);
137
+ }
138
+ };
139
+ var onKeyDown = function onKeyDown(event) {
140
+ if (!items || items.length === 0) return;
141
+ switch (event.key) {
142
+ case 'ArrowUp':
143
+ event.preventDefault();
144
+ handleArrowUp();
145
+ break;
146
+ case 'ArrowDown':
147
+ event.preventDefault();
148
+ handleArrowDown();
149
+ break;
150
+ case 'ArrowLeft':
151
+ if (columns > 1) {
152
+ event.preventDefault();
153
+ handleArrowLeft();
154
+ }
155
+ break;
156
+ case 'ArrowRight':
157
+ if (columns > 1) {
158
+ event.preventDefault();
159
+ handleArrowRight();
160
+ }
161
+ break;
162
+ case 'Enter':
163
+ event.preventDefault();
164
+ handleEnter();
165
+ break;
166
+ default:
167
+ }
168
+ };
169
+ return {
170
+ focusedKey: focusedKey,
171
+ onKeyDown: onKeyDown
172
+ };
173
+ }
@@ -47,8 +47,8 @@ export interface ListProps extends Omit<React.HTMLAttributes<HTMLUListElement>,
47
47
  */
48
48
  bordered?: boolean;
49
49
  /**
50
- * Set the focused item
51
- * */
50
+ * Set the focused item (controlled)
51
+ */
52
52
  focusedKey?: string | number;
53
53
  /**
54
54
  * Render list item as a function
@@ -58,6 +58,33 @@ export interface ListProps extends Omit<React.HTMLAttributes<HTMLUListElement>,
58
58
  * Click event for list items
59
59
  */
60
60
  onClick?: (item: ListItemProps) => void;
61
+ /**
62
+ * Callback when focused item changes via keyboard navigation
63
+ */
64
+ onFocusChange?: (key: string | number) => void;
65
+ /**
66
+ * Enable virtual scrolling for large lists.
67
+ * Requires `height` to be set.
68
+ * @default false
69
+ */
70
+ virtual?: boolean;
71
+ /**
72
+ * Height of the scrollable container in pixels.
73
+ * Required when `virtual` is true.
74
+ */
75
+ height?: number;
76
+ /**
77
+ * Fixed height of each list item row in pixels.
78
+ * Used for virtual scroll calculation.
79
+ * @default 32
80
+ */
81
+ itemHeight?: number;
82
+ /**
83
+ * Number of columns in the list layout.
84
+ * When greater than 1, items are displayed in a grid.
85
+ * @default 1
86
+ */
87
+ columns?: number;
61
88
  }
62
89
  export type ListCtxType = {
63
90
  prefixCls: string;
@@ -1,5 +1,7 @@
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", "className", "items", "bordered", "focusedKey", "itemRender", "onClick"];
2
+ var _excluded = ["prefixCls", "className", "style", "items", "bordered", "focusedKey", "itemRender", "onClick", "onFocusChange", "virtual", "height", "itemHeight", "columns"];
3
+ 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; }
4
+ 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; }
3
5
  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
6
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
7
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
@@ -9,7 +11,9 @@ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) r
9
11
  import clsx from 'clsx';
10
12
  import React, { createContext, forwardRef, useContext } from 'react';
11
13
  import { GlobalContext } from "../Config-Provider";
14
+ import useVirtualList from "../hooks/useVirtualList";
12
15
  import mergeContextToProps from "../utils/mergeContextToProps";
16
+ import useListKeyboard from "./hooks/useListKeyboard";
13
17
  import ListItem from "./list-item";
14
18
  import "./style/index.less";
15
19
  export var ListCtx = /*#__PURE__*/createContext({});
@@ -20,36 +24,189 @@ var List = /*#__PURE__*/forwardRef(function (baseprops, ref) {
20
24
  var _props$prefixCls = props.prefixCls,
21
25
  prefixCls = _props$prefixCls === void 0 ? 'yee-list' : _props$prefixCls,
22
26
  className = props.className,
27
+ style = props.style,
23
28
  items = props.items,
24
29
  bordered = props.bordered,
25
- focusedKey = props.focusedKey,
30
+ controlledFocusedKey = props.focusedKey,
26
31
  itemRender = props.itemRender,
27
32
  onClick = props.onClick,
33
+ onFocusChange = props.onFocusChange,
34
+ _props$virtual = props.virtual,
35
+ virtual = _props$virtual === void 0 ? false : _props$virtual,
36
+ height = props.height,
37
+ _props$itemHeight = props.itemHeight,
38
+ itemHeight = _props$itemHeight === void 0 ? 32 : _props$itemHeight,
39
+ _props$columns = props.columns,
40
+ columns = _props$columns === void 0 ? 1 : _props$columns,
28
41
  rest = _objectWithoutProperties(props, _excluded);
29
- var cls = clsx(prefixCls, _defineProperty({}, "".concat(prefixCls, "-bordered"), bordered), className);
30
- var itemRenders = function itemRenders() {
31
- return Array.isArray(items) ? items.map(function (item, index) {
32
- if (typeof itemRender === 'function') {
33
- return itemRender(item);
42
+ var multiColumn = columns > 1;
43
+ var useVirtual = virtual && height !== null && height !== undefined && Array.isArray(items);
44
+ var safeItems = Array.isArray(items) ? items : [];
45
+
46
+ // Keyboard navigation
47
+ var _useListKeyboard = useListKeyboard({
48
+ items: safeItems,
49
+ columns: columns,
50
+ focusedKey: controlledFocusedKey,
51
+ onFocusChange: onFocusChange,
52
+ onClick: onClick
53
+ }),
54
+ focusedKey = _useListKeyboard.focusedKey,
55
+ onKeyDown = _useListKeyboard.onKeyDown;
56
+
57
+ // Virtual scroll — in multi-column mode, track rows not individual items
58
+ var rowCount = multiColumn ? Math.ceil(safeItems.length / columns) : safeItems.length;
59
+ var _useVirtualList = useVirtualList({
60
+ itemCount: useVirtual ? rowCount : 0,
61
+ itemHeight: itemHeight,
62
+ overscan: 4
63
+ }),
64
+ start = _useVirtualList.start,
65
+ end = _useVirtualList.end,
66
+ offsetY = _useVirtualList.offsetY,
67
+ totalHeight = _useVirtualList.totalHeight,
68
+ viewportRef = _useVirtualList.viewportRef,
69
+ onScroll = _useVirtualList.onScroll;
70
+ var cls = clsx(prefixCls, _defineProperty(_defineProperty({}, "".concat(prefixCls, "-bordered"), bordered), "".concat(prefixCls, "-grid"), multiColumn && !useVirtual), className);
71
+ var renderItem = function renderItem(item, index) {
72
+ if (typeof itemRender === 'function') {
73
+ return itemRender(item);
74
+ }
75
+ return /*#__PURE__*/React.createElement(ListItem, _extends({}, item, {
76
+ $key: item.key,
77
+ key: item.key || index
78
+ }));
79
+ };
80
+
81
+ // ----- Virtual + multi-column: render rows of N items -----
82
+ if (useVirtual && multiColumn) {
83
+ var visibleRows = [];
84
+ for (var rowIdx = start; rowIdx < end; rowIdx++) {
85
+ var rowItems = [];
86
+ for (var col = 0; col < columns; col++) {
87
+ var flatIdx = rowIdx * columns + col;
88
+ if (flatIdx < safeItems.length) {
89
+ rowItems.push({
90
+ item: safeItems[flatIdx],
91
+ flatIdx: flatIdx
92
+ });
93
+ }
94
+ }
95
+ visibleRows.push({
96
+ rowIdx: rowIdx,
97
+ rowItems: rowItems
98
+ });
99
+ }
100
+ return /*#__PURE__*/React.createElement("ul", _extends({
101
+ ref: ref,
102
+ className: cls,
103
+ tabIndex: 0,
104
+ "aria-label": "list",
105
+ onKeyDown: onKeyDown
106
+ }, rest), /*#__PURE__*/React.createElement(ListCtx.Provider, {
107
+ value: {
108
+ prefixCls: prefixCls,
109
+ focusedKey: focusedKey,
110
+ onClick: onClick
111
+ }
112
+ }, /*#__PURE__*/React.createElement("div", {
113
+ ref: viewportRef,
114
+ onScroll: onScroll,
115
+ style: {
116
+ height: height,
117
+ overflowY: 'auto'
34
118
  }
35
- return /*#__PURE__*/React.createElement(ListItem, _extends({}, item, {
36
- $key: item.key,
37
- key: item.key || index
119
+ }, /*#__PURE__*/React.createElement("div", {
120
+ style: {
121
+ height: totalHeight,
122
+ position: 'relative'
123
+ }
124
+ }, visibleRows.map(function (_ref, ri) {
125
+ var rowIdx = _ref.rowIdx,
126
+ rowItems = _ref.rowItems;
127
+ return /*#__PURE__*/React.createElement("div", {
128
+ key: rowIdx,
129
+ className: "".concat(prefixCls, "-grid-row"),
130
+ style: {
131
+ position: 'absolute',
132
+ top: 0,
133
+ left: 0,
134
+ right: 0,
135
+ height: itemHeight,
136
+ transform: "translateY(".concat(offsetY + ri * itemHeight, "px)"),
137
+ display: 'grid',
138
+ gridTemplateColumns: "repeat(".concat(columns, ", 1fr)")
139
+ }
140
+ }, rowItems.map(function (_ref2) {
141
+ var item = _ref2.item,
142
+ flatIdx = _ref2.flatIdx;
143
+ return renderItem(item, flatIdx);
38
144
  }));
39
- }) : null;
40
- };
145
+ })))));
146
+ }
147
+
148
+ // ----- Virtual single-column -----
149
+ if (useVirtual) {
150
+ var slicedItems = safeItems.slice(start, end);
151
+ return /*#__PURE__*/React.createElement("ul", _extends({
152
+ ref: ref,
153
+ className: cls,
154
+ tabIndex: 0,
155
+ "aria-label": "list",
156
+ onKeyDown: onKeyDown
157
+ }, rest), /*#__PURE__*/React.createElement(ListCtx.Provider, {
158
+ value: {
159
+ prefixCls: prefixCls,
160
+ focusedKey: focusedKey,
161
+ onClick: onClick
162
+ }
163
+ }, /*#__PURE__*/React.createElement("div", {
164
+ ref: viewportRef,
165
+ onScroll: onScroll,
166
+ style: {
167
+ height: height,
168
+ overflowY: 'auto'
169
+ }
170
+ }, /*#__PURE__*/React.createElement("div", {
171
+ style: {
172
+ height: totalHeight,
173
+ position: 'relative'
174
+ }
175
+ }, slicedItems.map(function (item, i) {
176
+ var element = renderItem(item, start + i);
177
+ return /*#__PURE__*/React.createElement("div", {
178
+ key: item.key || start + i,
179
+ style: {
180
+ position: 'absolute',
181
+ top: 0,
182
+ left: 0,
183
+ width: '100%',
184
+ height: itemHeight,
185
+ transform: "translateY(".concat(offsetY + i * itemHeight, "px)")
186
+ }
187
+ }, element);
188
+ })))));
189
+ }
190
+
191
+ // ----- Default mode (non-virtual) -----
41
192
  return /*#__PURE__*/React.createElement("ul", _extends({
42
193
  ref: ref,
43
194
  className: cls,
44
195
  tabIndex: 0,
45
- "aria-label": "list"
196
+ "aria-label": "list",
197
+ onKeyDown: onKeyDown,
198
+ style: multiColumn ? _objectSpread({
199
+ '--yee-list-columns': columns
200
+ }, style) : style
46
201
  }, rest), /*#__PURE__*/React.createElement(ListCtx.Provider, {
47
202
  value: {
48
203
  prefixCls: prefixCls,
49
204
  focusedKey: focusedKey,
50
205
  onClick: onClick
51
206
  }
52
- }, itemRenders()));
207
+ }, safeItems.map(function (item, index) {
208
+ return renderItem(item, index);
209
+ })));
53
210
  });
54
211
  List.displayName = 'List';
55
212
  export default List;