@oceanbase/design 1.0.0-alpha.15 → 1.0.0-alpha.17

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 (79) hide show
  1. package/dist/design.min.js +1 -1
  2. package/es/alert/index.d.ts +1 -1
  3. package/es/alert/index.js +4 -2
  4. package/es/filter/components/CountNumber.js +2 -1
  5. package/es/filter/components/FilterButton.d.ts +2 -0
  6. package/es/filter/components/FilterButton.js +6 -3
  7. package/es/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.d.ts +20 -0
  8. package/es/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.js +101 -0
  9. package/es/filter/components/FilterCascader/components/CascaderOption/OptionItem.d.ts +13 -0
  10. package/es/filter/components/FilterCascader/components/CascaderOption/OptionItem.js +44 -0
  11. package/es/filter/components/FilterCascader/components/FlatCascaderContent/index.d.ts +16 -0
  12. package/es/filter/components/FilterCascader/components/FlatCascaderContent/index.js +64 -0
  13. package/es/filter/components/FilterCascader/components/NormalCascaderContent.d.ts +24 -0
  14. package/es/filter/components/FilterCascader/components/NormalCascaderContent.js +284 -0
  15. package/es/filter/components/FilterCascader/constants.d.ts +7 -0
  16. package/es/filter/components/FilterCascader/constants.js +8 -0
  17. package/es/filter/components/FilterCascader/hooks/useCascaderCallbacks.d.ts +12 -0
  18. package/es/filter/components/FilterCascader/hooks/useCascaderCallbacks.js +101 -0
  19. package/es/filter/components/FilterCascader/hooks/useCascaderLabels.d.ts +9 -0
  20. package/es/filter/components/FilterCascader/hooks/useCascaderLabels.js +50 -0
  21. package/es/filter/components/FilterCascader/hooks/useNormalizedValue.d.ts +7 -0
  22. package/es/filter/components/FilterCascader/hooks/useNormalizedValue.js +53 -0
  23. package/es/filter/components/FilterCascader/index.d.ts +5 -0
  24. package/es/filter/components/FilterCascader/index.js +317 -0
  25. package/es/filter/components/FilterCascader/types.d.ts +56 -0
  26. package/es/filter/components/FilterCascader/types.js +1 -0
  27. package/es/filter/components/FilterCascader/utils/countUtils.d.ts +13 -0
  28. package/es/filter/components/FilterCascader/utils/countUtils.js +48 -0
  29. package/es/filter/components/FilterCascader/utils/pathUtils.d.ts +17 -0
  30. package/es/filter/components/FilterCascader/utils/pathUtils.js +91 -0
  31. package/es/filter/components/FilterCheckbox.js +29 -7
  32. package/es/filter/components/FilterWrap.js +30 -1
  33. package/es/filter/components/ResponsiveFilterGroup.js +252 -359
  34. package/es/filter/index.d.ts +1 -1
  35. package/es/filter/index.js +11 -7
  36. package/es/filter/style/index.js +9 -2
  37. package/es/filter/type.d.ts +5 -0
  38. package/es/table/index.d.ts +2 -2
  39. package/lib/alert/index.d.ts +1 -1
  40. package/lib/alert/index.js +3 -1
  41. package/lib/filter/components/CountNumber.js +2 -1
  42. package/lib/filter/components/FilterButton.d.ts +2 -0
  43. package/lib/filter/components/FilterButton.js +4 -2
  44. package/lib/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.d.ts +20 -0
  45. package/lib/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.js +91 -0
  46. package/lib/filter/components/FilterCascader/components/CascaderOption/OptionItem.d.ts +13 -0
  47. package/lib/filter/components/FilterCascader/components/CascaderOption/OptionItem.js +51 -0
  48. package/lib/filter/components/FilterCascader/components/FlatCascaderContent/index.d.ts +16 -0
  49. package/lib/filter/components/FilterCascader/components/FlatCascaderContent/index.js +70 -0
  50. package/lib/filter/components/FilterCascader/components/NormalCascaderContent.d.ts +24 -0
  51. package/lib/filter/components/FilterCascader/components/NormalCascaderContent.js +263 -0
  52. package/lib/filter/components/FilterCascader/constants.d.ts +7 -0
  53. package/lib/filter/components/FilterCascader/constants.js +14 -0
  54. package/lib/filter/components/FilterCascader/hooks/useCascaderCallbacks.d.ts +12 -0
  55. package/lib/filter/components/FilterCascader/hooks/useCascaderCallbacks.js +81 -0
  56. package/lib/filter/components/FilterCascader/hooks/useCascaderLabels.d.ts +9 -0
  57. package/lib/filter/components/FilterCascader/hooks/useCascaderLabels.js +56 -0
  58. package/lib/filter/components/FilterCascader/hooks/useNormalizedValue.d.ts +7 -0
  59. package/lib/filter/components/FilterCascader/hooks/useNormalizedValue.js +48 -0
  60. package/lib/filter/components/FilterCascader/index.d.ts +5 -0
  61. package/lib/filter/components/FilterCascader/index.js +298 -0
  62. package/lib/filter/components/FilterCascader/types.d.ts +56 -0
  63. package/lib/filter/components/FilterCascader/types.js +5 -0
  64. package/lib/filter/components/FilterCascader/utils/countUtils.d.ts +13 -0
  65. package/lib/filter/components/FilterCascader/utils/countUtils.js +49 -0
  66. package/lib/filter/components/FilterCascader/utils/pathUtils.d.ts +17 -0
  67. package/lib/filter/components/FilterCascader/utils/pathUtils.js +56 -0
  68. package/lib/filter/components/FilterCheckbox.js +29 -7
  69. package/lib/filter/components/FilterWrap.js +28 -1
  70. package/lib/filter/components/ResponsiveFilterGroup.js +214 -340
  71. package/lib/filter/index.d.ts +1 -1
  72. package/lib/filter/index.js +11 -7
  73. package/lib/filter/style/index.js +10 -1
  74. package/lib/filter/type.d.ts +5 -0
  75. package/package.json +3 -3
  76. package/es/filter/components/FilterCascader.d.ts +0 -31
  77. package/es/filter/components/FilterCascader.js +0 -529
  78. package/lib/filter/components/FilterCascader.d.ts +0 -31
  79. package/lib/filter/components/FilterCascader.js +0 -449
@@ -15,8 +15,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
15
15
  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; }
16
16
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
17
17
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
18
- import React, { Children, cloneElement, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react';
19
- import { createPortal } from 'react-dom';
18
+ import React, { Children, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
20
19
  import { Flex } from 'antd';
21
20
  import { FilterOutlined } from '@oceanbase/icons';
22
21
  import Button from "../../button";
@@ -26,33 +25,24 @@ import defaultLocale from "../../locale/en-US";
26
25
  import { FilterProvider } from "../FilterContext";
27
26
  import { jsx as _jsx } from "react/jsx-runtime";
28
27
  import { jsxs as _jsxs } from "react/jsx-runtime";
29
- import { Fragment as _Fragment } from "react/jsx-runtime";
30
- /**
31
- * ResponsiveFilterGroup 组件
32
- *
33
- * 响应式 Filter 容器,当宽度不足时自动将后面的 Filter 收起到 FilterWrap
34
- *
35
- * @example
36
- * ```tsx
37
- * <ResponsiveFilterGroup onApply={handleSearch} onClearAll={handleReset}>
38
- * <Filter.Select label="操作者" ... />
39
- * <Filter.Cascader label="事件操作" ... />
40
- * <Filter.Select label="执行结果" ... />
41
- * </ResponsiveFilterGroup>
42
- * ```
43
- */
44
- // 检查子元素是否可以被收集
45
- var isCollapsible = function isCollapsible(child) {
46
- // 检查子元素的 props 中是否有 collapsible 属性
47
- // 如果子元素是 Form.Item,需要检查其子元素的 props
48
- var childProps = child.props;
28
+ // 检查元素是否是 Filter 组件(通过 __isFilterComponent 静态标记识别)
29
+ var isFilterComponent = function isFilterComponent(child) {
30
+ var _child$props;
31
+ var type = child.type;
32
+ if (type !== null && type !== void 0 && type.__isFilterComponent) return true;
33
+ if ((_child$props = child.props) !== null && _child$props !== void 0 && _child$props.children && /*#__PURE__*/isValidElement(child.props.children)) {
34
+ var innerType = child.props.children.type;
35
+ if (innerType !== null && innerType !== void 0 && innerType.__isFilterComponent) return true;
36
+ }
37
+ return false;
38
+ };
49
39
 
50
- // 直接检查 collapsible 属性
40
+ // 检查子元素是否可以被折叠(只有 Filter 组件默认可折叠,其他组件需要显式设置 collapsible
41
+ var isCollapsibleCheck = function isCollapsibleCheck(child) {
42
+ var childProps = child.props;
51
43
  if ((childProps === null || childProps === void 0 ? void 0 : childProps.collapsible) !== undefined) {
52
44
  return childProps.collapsible !== false;
53
45
  }
54
-
55
- // 如果是 Form.Item 等包装组件,检查其 children 的 collapsible
56
46
  if (childProps !== null && childProps !== void 0 && childProps.children && /*#__PURE__*/isValidElement(childProps.children)) {
57
47
  var _innerChild$props;
58
48
  var innerChild = childProps.children;
@@ -60,21 +50,15 @@ var isCollapsible = function isCollapsible(child) {
60
50
  return innerChild.props.collapsible !== false;
61
51
  }
62
52
  }
63
-
64
- // 默认可以被收集
65
- return true;
53
+ return isFilterComponent(child);
66
54
  };
67
55
 
68
56
  // 检查子元素是否应该始终折叠
69
- var isAlwaysCollapse = function isAlwaysCollapse(child) {
57
+ var isAlwaysCollapseCheck = function isAlwaysCollapseCheck(child) {
70
58
  var childProps = child.props;
71
-
72
- // 直接检查 alwaysCollapse 属性
73
59
  if ((childProps === null || childProps === void 0 ? void 0 : childProps.alwaysCollapse) !== undefined) {
74
60
  return childProps.alwaysCollapse === true;
75
61
  }
76
-
77
- // 如果是 Form.Item 等包装组件,检查其 children 的 alwaysCollapse
78
62
  if (childProps !== null && childProps !== void 0 && childProps.children && /*#__PURE__*/isValidElement(childProps.children)) {
79
63
  var _innerChild$props2;
80
64
  var innerChild = childProps.children;
@@ -82,8 +66,6 @@ var isAlwaysCollapse = function isAlwaysCollapse(child) {
82
66
  return innerChild.props.alwaysCollapse === true;
83
67
  }
84
68
  }
85
-
86
- // 默认不始终折叠
87
69
  return false;
88
70
  };
89
71
  var ResponsiveFilterGroup = function ResponsiveFilterGroup(_ref) {
@@ -105,262 +87,182 @@ var ResponsiveFilterGroup = function ResponsiveFilterGroup(_ref) {
105
87
  var _useContext = useContext(ConfigProvider.ConfigContext),
106
88
  contextLocale = _useContext.locale;
107
89
  var filterLocale = _objectSpread(_objectSpread(_objectSpread({}, defaultLocale.Filter), contextLocale === null || contextLocale === void 0 ? void 0 : contextLocale.Filter), customLocale);
108
- // 如果没有传入 label,使用国际化默认值
109
90
  var filterLabel = label !== null && label !== void 0 ? label : filterLocale === null || filterLocale === void 0 ? void 0 : filterLocale.filters;
110
91
  var containerRef = useRef(null);
111
- var innerFlexRef = useRef(null);
112
- var measureRef = useRef(null);
113
- var unmeasureRef = useRef(null);
114
- var moreButtonRef = useRef(null);
115
92
  var filterButtonRef = useRef(null);
116
- var _useState = useState(-1),
93
+ var moreButtonMeasureRef = useRef(null);
94
+ var cachedWidths = useRef([]);
95
+ var _useState = useState(null),
117
96
  _useState2 = _slicedToArray(_useState, 2),
118
97
  visibleCount = _useState2[0],
119
- setVisibleCount = _useState2[1]; // -1 表示还未计算
98
+ setVisibleCount = _useState2[1];
120
99
  var _useState3 = useState([]),
121
100
  _useState4 = _slicedToArray(_useState3, 2),
122
- childWidths = _useState4[0],
123
- setChildWidths = _useState4[1];
124
- // 不再依赖外部传入的预留宽度,初始为 0,后续通过真实 DOM 测量获得
125
- var _useState5 = useState(0),
101
+ filterValues = _useState4[0],
102
+ setFilterValues = _useState4[1];
103
+ var childrenArray = useMemo(function () {
104
+ return Children.toArray(children).filter(isValidElement);
105
+ }, [children]);
106
+ var childInfo = useMemo(function () {
107
+ return childrenArray.map(function (child, index) {
108
+ return {
109
+ child: child,
110
+ index: index,
111
+ isCollapsible: isCollapsibleCheck(child),
112
+ isAlwaysCollapse: isAlwaysCollapseCheck(child)
113
+ };
114
+ });
115
+ }, [childrenArray]);
116
+ var collapsibleItems = useMemo(function () {
117
+ return childInfo.filter(function (item) {
118
+ return item.isCollapsible;
119
+ });
120
+ }, [childInfo]);
121
+ var alwaysCollapseItems = useMemo(function () {
122
+ return collapsibleItems.filter(function (item) {
123
+ return item.isAlwaysCollapse;
124
+ });
125
+ }, [collapsibleItems]);
126
+ var normalCollapsibleItems = useMemo(function () {
127
+ return collapsibleItems.filter(function (item) {
128
+ return !item.isAlwaysCollapse;
129
+ });
130
+ }, [collapsibleItems]);
131
+
132
+ // 当 children 结构变化(增删/重排)时才重置为测量模式
133
+ // 不能用 childrenArray 引用比较,因为 JSX 每次渲染都产生新引用
134
+ var childrenStructureKey = childrenArray.map(function (c) {
135
+ var _c$key;
136
+ return (_c$key = c.key) !== null && _c$key !== void 0 ? _c$key : c.type;
137
+ }).join(',');
138
+ var _useState5 = useState(childrenStructureKey),
126
139
  _useState6 = _slicedToArray(_useState5, 2),
127
- actualMoreButtonWidth = _useState6[0],
128
- setActualMoreButtonWidth = _useState6[1];
129
- var _useState7 = useState(0),
130
- _useState8 = _slicedToArray(_useState7, 2),
131
- unCollapsibleWidth = _useState8[0],
132
- setUnCollapsibleWidth = _useState8[1];
133
- var _useState9 = useState(null),
134
- _useState10 = _slicedToArray(_useState9, 2),
135
- measureContainer = _useState10[0],
136
- setMeasureContainer = _useState10[1];
137
- // 维护筛选值的数组
138
- var _useState11 = useState([]),
139
- _useState12 = _slicedToArray(_useState11, 2),
140
- filterValues = _useState12[0],
141
- setFilterValues = _useState12[1];
142
- var childrenArray = Children.toArray(children).filter(isValidElement);
143
-
144
- // 分离不可收集和可收集的子元素
145
- var unCollapsibleChildren = childrenArray.filter(function (child) {
146
- return !isCollapsible(child);
147
- });
148
- var collapsibleChildren = childrenArray.filter(function (child) {
149
- return isCollapsible(child);
150
- });
151
-
152
- // 分离始终折叠和普通可收集的子元素
153
- var alwaysCollapseChildren = collapsibleChildren.filter(function (child) {
154
- return isAlwaysCollapse(child);
155
- });
156
- var normalCollapsibleChildren = collapsibleChildren.filter(function (child) {
157
- return !isAlwaysCollapse(child);
158
- });
159
-
160
- // 创建测量容器
161
- useEffect(function () {
162
- var container = document.createElement('div');
163
- container.style.cssText = 'position: absolute; visibility: hidden; pointer-events: none; top: -9999px; left: -9999px;';
164
- document.body.appendChild(container);
165
- setMeasureContainer(container);
166
- return function () {
167
- document.body.removeChild(container);
168
- };
169
- }, []);
170
-
171
- // 测量每个可收集子元素的宽度(只测量普通可收集的,不包括始终折叠的)
172
- var measureChildren = useCallback(function () {
173
- if (!measureRef.current) return;
174
-
175
- // 测量普通可收集子元素宽度
176
- var widths = [];
177
- if (measureRef.current) {
178
- var measureDiv = measureRef.current;
179
- var measureItems = measureDiv.children;
180
- for (var i = 0; i < measureItems.length; i++) {
181
- var item = measureItems[i];
182
- widths.push(item.offsetWidth);
183
- }
184
- }
185
- setChildWidths(widths);
186
-
187
- // 测量 more button 的宽度
188
- if (moreButtonRef.current) {
189
- setActualMoreButtonWidth(moreButtonRef.current.offsetWidth);
190
- }
191
-
192
- // 测量不可收集子元素的总宽度(使用隐藏测量容器,保证与普通可收集项的测量方式一致)
193
- if (unmeasureRef.current) {
194
- var sum = 0;
195
- var items = unmeasureRef.current.children;
196
- for (var _i = 0; _i < items.length; _i++) {
197
- var it = items[_i];
198
- sum += it.offsetWidth;
140
+ prevStructureKey = _useState6[0],
141
+ setPrevStructureKey = _useState6[1];
142
+ if (childrenStructureKey !== prevStructureKey) {
143
+ setPrevStructureKey(childrenStructureKey);
144
+ setVisibleCount(null);
145
+ }
146
+ var isMeasuring = visibleCount === null;
147
+
148
+ // 纯计算函数:根据容器宽度计算可显示的可折叠项数量
149
+ var calculateVisibleCount = useCallback(function (containerWidth) {
150
+ var _moreButtonMeasureRef;
151
+ if (normalCollapsibleItems.length === 0) return 0;
152
+ var widths = cachedWidths.current;
153
+ if (widths.length === 0) return normalCollapsibleItems.length;
154
+ var uncollapsibleTotalWidth = 0;
155
+ var uncollapsibleCount = 0;
156
+ childInfo.forEach(function (info) {
157
+ if (!info.isCollapsible) {
158
+ uncollapsibleTotalWidth += widths[info.index] || 0;
159
+ uncollapsibleCount++;
199
160
  }
200
- setUnCollapsibleWidth(sum || 0);
201
- } else {
202
- setUnCollapsibleWidth(0);
203
- }
204
- }, [unCollapsibleChildren.length, normalCollapsibleChildren.length, gap]);
205
-
206
- // 计算可见的可收集子元素数量(只计算普通可收集的,不包括始终折叠的)
207
- var calculateVisibleCount = useCallback(function () {
208
- if (!containerRef.current) return;
209
- // 如果没有普通可收集的子元素,显示全部(0表示全部折叠)
210
- if (normalCollapsibleChildren.length === 0) {
211
- setVisibleCount(0);
212
- return;
213
- }
214
- if (childWidths.length === 0) return;
215
-
216
- // 可用宽度 = 容器宽度 - 不可收集子元素占用的宽度 - 可能存在的间隙
217
- var containerWidth = containerRef.current.offsetWidth;
218
- var gapBetweenUncollapsibleAndCollapsible = unCollapsibleChildren.length > 0 && normalCollapsibleChildren.length > 0 ? gap : 0;
219
- var availableWidth = containerWidth - (unCollapsibleWidth || 0) - gapBetweenUncollapsibleAndCollapsible;
220
- var totalWidth = 0;
161
+ });
162
+ var moreWidth = ((_moreButtonMeasureRef = moreButtonMeasureRef.current) === null || _moreButtonMeasureRef === void 0 ? void 0 : _moreButtonMeasureRef.offsetWidth) || 0;
163
+ var hasAlwaysCollapse = alwaysCollapseItems.length > 0;
164
+ var visibleWidth = 0;
221
165
  var count = 0;
222
-
223
- // 如果有始终折叠的元素,需要预留 more button 的宽度
224
- var hasAlwaysCollapse = alwaysCollapseChildren.length > 0;
225
- var reservedForMoreButton = hasAlwaysCollapse ? actualMoreButtonWidth + gap : 0;
226
- for (var i = 0; i < childWidths.length; i++) {
227
- var itemWidth = childWidths[i] + (i > 0 ? gap : 0);
228
- // 检查是否还有空间放置当前元素
229
- // 如果不是最后一个元素,需要预留实际测量到的更多按钮宽度
230
- var needMoreButton = i < childWidths.length - 1;
231
- var reservedWidth = needMoreButton ? actualMoreButtonWidth + gap : reservedForMoreButton;
232
- if (totalWidth + itemWidth + reservedWidth <= availableWidth) {
233
- totalWidth += itemWidth;
166
+ for (var i = 0; i < normalCollapsibleItems.length; i++) {
167
+ var itemWidth = widths[normalCollapsibleItems[i].index] || 0;
168
+ var newWidth = visibleWidth + itemWidth;
169
+ var remaining = normalCollapsibleItems.length - i - 1;
170
+ var needMore = remaining > 0 || hasAlwaysCollapse;
171
+ var totalItems = uncollapsibleCount + count + 1 + (needMore ? 1 : 0);
172
+ var totalGaps = totalItems > 1 ? (totalItems - 1) * gap : 0;
173
+ var totalWidth = uncollapsibleTotalWidth + newWidth + (needMore ? moreWidth : 0) + totalGaps;
174
+ if (totalWidth <= containerWidth) {
175
+ visibleWidth = newWidth;
234
176
  count++;
235
177
  } else {
236
178
  break;
237
179
  }
238
180
  }
181
+ return count;
182
+ }, [childInfo, normalCollapsibleItems, alwaysCollapseItems, gap]);
239
183
 
240
- // 如果所有元素都能显示,就显示全部
241
- if (count === childWidths.length) {
242
- setVisibleCount(childWidths.length);
243
- } else if (count === 0) {
244
- // 如果一个都放不下,只显示 more button
245
- setVisibleCount(0);
246
- } else {
247
- setVisibleCount(count);
248
- }
249
- }, [childWidths, gap, actualMoreButtonWidth, normalCollapsibleChildren.length, alwaysCollapseChildren.length, unCollapsibleWidth, unCollapsibleChildren.length]);
184
+ // 使用 ref 保存最新的计算函数,避免 ResizeObserver 等 effect 频繁重建
185
+ var calculateRef = useRef(calculateVisibleCount);
186
+ calculateRef.current = calculateVisibleCount;
250
187
 
251
- // 初始测量 - 使用 useLayoutEffect 确保在绘制前完成
188
+ // Effect 1: 测量模式下,读取所有子元素宽度并计算 visibleCount
252
189
  useLayoutEffect(function () {
253
- if (measureContainer) {
254
- // 延迟一帧确保 portal 已渲染
255
- requestAnimationFrame(function () {
256
- measureChildren();
257
- });
258
- }
259
- }, [children, measureChildren, measureContainer, normalCollapsibleChildren]);
190
+ if (!containerRef.current || !isMeasuring) return;
191
+ var items = containerRef.current.querySelectorAll('[data-filter-item]');
192
+ var newWidths = [];
193
+ items.forEach(function (el) {
194
+ var idx = Number(el.dataset.filterItem);
195
+ if (!isNaN(idx)) {
196
+ newWidths[idx] = el.offsetWidth;
197
+ }
198
+ });
199
+ cachedWidths.current = newWidths;
200
+ var count = calculateRef.current(containerRef.current.offsetWidth);
201
+ setVisibleCount(count);
202
+ }, [isMeasuring]);
260
203
 
261
- // filterValues 改变时,more 按钮可能会显示 badge,导致宽度变化,需重新测量
204
+ // Effect 2: 监听容器大小变化,用缓存宽度重新计算(不需要重新测量)
262
205
  useEffect(function () {
263
- if (measureContainer) {
264
- requestAnimationFrame(function () {
265
- measureChildren();
206
+ if (!containerRef.current) return;
207
+ var el = containerRef.current;
208
+ var ro = new ResizeObserver(function () {
209
+ if (cachedWidths.current.length === 0) return;
210
+ var count = calculateRef.current(el.offsetWidth);
211
+ setVisibleCount(function (prev) {
212
+ return prev === count ? prev : count;
266
213
  });
267
- }
268
- }, [filterValues, measureChildren, measureContainer]);
269
-
270
- // 当 childWidths 更新后计算可见数量
271
- useLayoutEffect(function () {
272
- calculateVisibleCount();
273
- }, [childWidths, unCollapsibleWidth, calculateVisibleCount]);
274
-
275
- // 监听窗口大小变化
276
- useEffect(function () {
277
- var handleResize = function handleResize() {
278
- calculateVisibleCount();
279
- };
280
- window.addEventListener('resize', handleResize);
214
+ });
215
+ ro.observe(el);
281
216
  return function () {
282
- window.removeEventListener('resize', handleResize);
217
+ return ro.disconnect();
283
218
  };
284
- }, [calculateVisibleCount]);
219
+ }, []);
285
220
 
286
- // 监听容器大小变化
221
+ // Effect 3: filterValues 变化时,more 按钮 badge 可能变化,需要重新计算
287
222
  useEffect(function () {
288
- if (!containerRef.current) return;
289
- var resizeObserver = new ResizeObserver(function () {
290
- calculateVisibleCount();
223
+ if (!containerRef.current || cachedWidths.current.length === 0) return;
224
+ var count = calculateRef.current(containerRef.current.offsetWidth);
225
+ setVisibleCount(function (prev) {
226
+ return prev === count ? prev : count;
291
227
  });
292
- resizeObserver.observe(containerRef.current);
293
- return function () {
294
- resizeObserver.disconnect();
295
- };
296
- }, [calculateVisibleCount]);
297
-
298
- // 分离可见和隐藏的普通可收集子元素(始终折叠的不参与计算)
299
- var visibleCollapsibleChildren = visibleCount === -1 ? normalCollapsibleChildren : normalCollapsibleChildren.slice(0, visibleCount);
300
- var hiddenCollapsibleChildren = visibleCount === -1 ? [] : normalCollapsibleChildren.slice(visibleCount);
301
-
302
- // 合并始终折叠和隐藏的普通可收集子元素
303
- var allHiddenChildren = [].concat(_toConsumableArray(alwaysCollapseChildren), _toConsumableArray(hiddenCollapsibleChildren));
304
-
305
- // 递归地为子元素添加 _isCollapsed prop
306
- var addIsInWrapProp = function addIsInWrapProp(element) {
307
- var childProps = element.props;
308
-
309
- // 对当前元素添加 _isCollapsed prop
310
- var newProps = {
311
- _isCollapsed: true
312
- };
313
-
314
- // 如果有 children,递归处理
315
- if (childProps !== null && childProps !== void 0 && childProps.children) {
316
- if ( /*#__PURE__*/isValidElement(childProps.children)) {
317
- // 单个子元素
318
- newProps.children = addIsInWrapProp(childProps.children);
319
- } else if (Array.isArray(childProps.children)) {
320
- // 多个子元素
321
- newProps.children = childProps.children.map(function (child) {
322
- if ( /*#__PURE__*/isValidElement(child)) {
323
- return addIsInWrapProp(child);
324
- }
325
- return child;
326
- });
327
- }
328
- }
329
- return /*#__PURE__*/cloneElement(element, newProps);
330
- };
228
+ }, [filterValues]);
229
+
230
+ // --- 派生状态 ---
231
+ var visibleIndexSet = useMemo(function () {
232
+ if (visibleCount === null) return null;
233
+ return new Set(normalCollapsibleItems.slice(0, visibleCount).map(function (item) {
234
+ return item.index;
235
+ }));
236
+ }, [visibleCount, normalCollapsibleItems]);
237
+ var hiddenCollapsibleItems = useMemo(function () {
238
+ if (!visibleIndexSet) return [];
239
+ return normalCollapsibleItems.filter(function (item) {
240
+ return !visibleIndexSet.has(item.index);
241
+ });
242
+ }, [visibleIndexSet, normalCollapsibleItems]);
243
+ var allHiddenItems = useMemo(function () {
244
+ return [].concat(_toConsumableArray(alwaysCollapseItems), _toConsumableArray(hiddenCollapsibleItems));
245
+ }, [alwaysCollapseItems, hiddenCollapsibleItems]);
331
246
 
332
- // 更新筛选值的函数
247
+ // --- 值管理 ---
333
248
  var updateFilterValue = useCallback(function (id, _filterLabel, value, options, componentName) {
334
249
  setFilterValues(function (prev) {
335
- // 如果值为空,移除该项
336
- // 对于 switch 组件,false 被视为未选中状态,应该被视为空值
337
- var isEmpty = value === undefined || value === null || value === '' || componentName === 'switch' && value === false ||
338
- // switch 组件的 false 值视为空
339
- Array.isArray(value) && value.length === 0;
250
+ var isEmpty = value === undefined || value === null || value === '' || componentName === 'switch' && value === false || Array.isArray(value) && value.length === 0;
340
251
  if (isEmpty) {
341
252
  var filtered = prev.filter(function (item) {
342
253
  return item.id !== id;
343
254
  });
344
- // 如果数组长度没变化,说明该项本来就不存在,直接返回原数组
345
- if (filtered.length === prev.length) {
346
- return prev;
347
- }
348
- return filtered;
255
+ return filtered.length === prev.length ? prev : filtered;
349
256
  }
350
- // 查找是否已存在
351
257
  var existingIndex = prev.findIndex(function (item) {
352
258
  return item.id === id;
353
259
  });
354
260
  if (existingIndex >= 0) {
355
- var existingItem = prev[existingIndex];
356
- // 深度比较 options 是否相等
357
- var optionsEqual = existingItem.options === options || existingItem.options === undefined && options === undefined || existingItem.options !== undefined && options !== undefined && JSON.stringify(existingItem.options) === JSON.stringify(options);
358
-
359
- // 如果值、选项和组件名都没变化,直接返回原数组
360
- if (existingItem.value === value && optionsEqual && existingItem.componentName === componentName && existingItem.label === _filterLabel) {
261
+ var existing = prev[existingIndex];
262
+ var optionsEqual = existing.options === options || existing.options === undefined && options === undefined || existing.options !== undefined && options !== undefined && JSON.stringify(existing.options) === JSON.stringify(options);
263
+ if (existing.value === value && optionsEqual && existing.componentName === componentName && existing.label === _filterLabel) {
361
264
  return prev;
362
265
  }
363
- // 更新已存在的项
364
266
  var newValues = _toConsumableArray(prev);
365
267
  newValues[existingIndex] = {
366
268
  id: id,
@@ -370,43 +272,37 @@ var ResponsiveFilterGroup = function ResponsiveFilterGroup(_ref) {
370
272
  componentName: componentName
371
273
  };
372
274
  return newValues;
373
- } else {
374
- // 添加新项
375
- return [].concat(_toConsumableArray(prev), [{
376
- id: id,
377
- label: _filterLabel,
378
- value: value,
379
- options: options,
380
- componentName: componentName
381
- }]);
382
275
  }
276
+ return [].concat(_toConsumableArray(prev), [{
277
+ id: id,
278
+ label: _filterLabel,
279
+ value: value,
280
+ options: options,
281
+ componentName: componentName
282
+ }]);
383
283
  });
384
284
  }, []);
385
285
  var handleClearAll = function handleClearAll() {
386
- // 先清除所有子组件的值
387
- allHiddenChildren.forEach(function (child) {
388
- if ( /*#__PURE__*/isValidElement(child)) {
389
- var childProps = child.props;
390
- // 如果是 Form.Item,需要访问其子组件
286
+ allHiddenItems.forEach(function (item) {
287
+ if ( /*#__PURE__*/isValidElement(item.child)) {
288
+ var childProps = item.child.props;
391
289
  if (childProps.children && /*#__PURE__*/isValidElement(childProps.children)) {
290
+ var _innerChildProps$onCh;
392
291
  var innerChildProps = childProps.children.props;
393
- if (innerChildProps.onChange) {
394
- innerChildProps.onChange(undefined);
395
- }
396
- } else if (childProps.onChange) {
397
- childProps.onChange(undefined);
292
+ (_innerChildProps$onCh = innerChildProps.onChange) === null || _innerChildProps$onCh === void 0 || _innerChildProps$onCh.call(innerChildProps, undefined);
293
+ } else {
294
+ var _childProps$onChange;
295
+ (_childProps$onChange = childProps.onChange) === null || _childProps$onChange === void 0 || _childProps$onChange.call(childProps, undefined);
398
296
  }
399
297
  }
400
298
  });
401
- // 然后清除 filterValues
402
299
  setFilterValues([]);
403
- // 最后调用外部回调
404
- onClearAll();
300
+ onClearAll === null || onClearAll === void 0 || onClearAll();
405
301
  };
406
302
 
407
- // 渲染隐藏的可收集子元素到 FilterWrap 中(包括始终折叠和隐藏的普通可收集子元素)
303
+ // --- 渲染 FilterWrap(收起的筛选项) ---
408
304
  var renderHiddenChildren = function renderHiddenChildren() {
409
- if (allHiddenChildren.length === 0) return null;
305
+ if (allHiddenItems.length === 0) return null;
410
306
  return /*#__PURE__*/_jsx(FilterProvider, {
411
307
  isCollapsed: true,
412
308
  filterValues: filterValues,
@@ -418,6 +314,7 @@ var ResponsiveFilterGroup = function ResponsiveFilterGroup(_ref) {
418
314
  label: filterLabel,
419
315
  extra: extra,
420
316
  onClearAll: handleClearAll,
317
+ showCount: showCount,
421
318
  footer: showActions && /*#__PURE__*/_jsxs(Flex, {
422
319
  justify: "space-between",
423
320
  children: [onApply && /*#__PURE__*/_jsx(Button, {
@@ -436,86 +333,94 @@ var ResponsiveFilterGroup = function ResponsiveFilterGroup(_ref) {
436
333
  children: filterLocale === null || filterLocale === void 0 ? void 0 : filterLocale.clearAll
437
334
  })]
438
335
  }),
439
- children: allHiddenChildren.map(function (child, index) {
440
- if ( /*#__PURE__*/isValidElement(child)) {
441
- // 使用 child.key 或生成稳定的 key
442
- var stableKey = child.key || "responsive-filter-child-".concat(index);
336
+ children: allHiddenItems.map(function (item, index) {
337
+ if ( /*#__PURE__*/isValidElement(item.child)) {
338
+ var stableKey = item.child.key || "responsive-filter-child-".concat(index);
443
339
  return /*#__PURE__*/_jsx(React.Fragment, {
444
- children: addIsInWrapProp(child)
340
+ children: item.child
445
341
  }, stableKey);
446
342
  }
447
- return child;
343
+ return item.child;
448
344
  })
449
345
  })
450
346
  });
451
347
  };
452
348
 
453
- // 测量容器内容 - 使用 Portal 渲染到 body 外部,避免影响布局计算
454
- // 只测量可收集的子元素
455
- var measureContent = measureContainer ? /*#__PURE__*/createPortal( /*#__PURE__*/_jsxs(_Fragment, {
456
- children: [/*#__PURE__*/_jsx("div", {
457
- ref: unmeasureRef,
458
- style: {
459
- display: 'flex',
460
- gap: gap,
461
- whiteSpace: 'nowrap'
462
- },
463
- children: unCollapsibleChildren.map(function (child, index) {
464
- var stableKey = /*#__PURE__*/isValidElement(child) && child.key ? child.key : "measure-unc-".concat(index);
465
- return /*#__PURE__*/_jsx("div", {
349
+ // --- 渲染子元素 ---
350
+ // 所有子元素始终保持在 Flex 中的稳定位置(FilterProvider + div 包裹 + 稳定 key),
351
+ // 通过 CSS display 控制显隐,避免在可见/折叠间切换时卸载重挂载导致表单值丢失。
352
+ // FilterProvider 使隐藏的原始组件能直接感知 isCollapsed 并上报值,无需依赖 Popover 中的克隆。
353
+ var renderChildren = function renderChildren() {
354
+ var elements = [];
355
+ var filterWrapInserted = false;
356
+ var collapsibleIdx = 0;
357
+ childrenArray.forEach(function (child, index) {
358
+ var info = childInfo[index];
359
+ var stableKey = child.key || "filter-item-".concat(index);
360
+ var display;
361
+ var isHidden = false;
362
+ if (isMeasuring) {
363
+ display = 'inline-flex';
364
+ } else if (!info.isCollapsible) {
365
+ display = undefined;
366
+ } else if (info.isAlwaysCollapse) {
367
+ display = 'none';
368
+ isHidden = true;
369
+ } else {
370
+ var isVisible = collapsibleIdx < visibleCount;
371
+ display = isVisible ? undefined : 'none';
372
+ isHidden = !isVisible;
373
+ collapsibleIdx++;
374
+ }
375
+ elements.push( /*#__PURE__*/_jsx(FilterProvider, {
376
+ isCollapsed: !isMeasuring && isHidden,
377
+ filterValues: filterValues,
378
+ updateFilterValue: updateFilterValue,
379
+ children: /*#__PURE__*/_jsx("div", {
380
+ "data-filter-item": isMeasuring ? index : undefined,
466
381
  style: {
467
- display: 'inline-flex'
382
+ display: display
468
383
  },
469
384
  children: child
470
- }, stableKey);
471
- })
472
- }), /*#__PURE__*/_jsx("div", {
473
- ref: measureRef,
385
+ })
386
+ }, stableKey));
387
+ if (!isMeasuring && isHidden && !filterWrapInserted && allHiddenItems.length > 0) {
388
+ filterWrapInserted = true;
389
+ elements.push( /*#__PURE__*/_jsx(React.Fragment, {
390
+ children: renderHiddenChildren()
391
+ }, "filter-wrap"));
392
+ }
393
+ });
394
+ if (!isMeasuring && !filterWrapInserted && allHiddenItems.length > 0) {
395
+ elements.push( /*#__PURE__*/_jsx(React.Fragment, {
396
+ children: renderHiddenChildren()
397
+ }, "filter-wrap"));
398
+ }
399
+ return elements;
400
+ };
401
+ return /*#__PURE__*/_jsxs("div", {
402
+ ref: containerRef,
403
+ className: "responsive-filter-group",
404
+ style: _objectSpread({
405
+ flex: '1 1 auto',
406
+ minWidth: 0,
407
+ position: 'relative',
408
+ visibility: isMeasuring ? 'hidden' : undefined
409
+ }, style),
410
+ children: [/*#__PURE__*/_jsx("div", {
411
+ ref: moreButtonMeasureRef,
474
412
  style: {
475
- display: 'flex',
476
- gap: gap,
477
- whiteSpace: 'nowrap'
413
+ position: 'absolute',
414
+ visibility: 'hidden',
415
+ pointerEvents: 'none',
416
+ top: -9999,
417
+ left: -9999,
418
+ display: 'inline-flex'
478
419
  },
479
- children: normalCollapsibleChildren.map(function (child, index) {
480
- // 使用 child.key 或生成稳定的 key
481
- var stableKey = /*#__PURE__*/isValidElement(child) && child.key ? child.key : "measure-child-".concat(index);
482
- return /*#__PURE__*/_jsx("div", {
483
- style: {
484
- display: 'inline-flex'
485
- },
486
- children: child
487
- }, stableKey);
488
- })
489
- }), /*#__PURE__*/_jsx(FilterProvider, {
490
- isCollapsed: true,
491
- filterValues: filterValues,
492
- updateFilterValue: updateFilterValue,
493
- children: /*#__PURE__*/_jsx("div", {
494
- style: {
495
- position: 'absolute',
496
- visibility: 'hidden',
497
- pointerEvents: 'none',
498
- top: -9999,
499
- left: -9999
500
- },
501
- children: allHiddenChildren.map(function (child, index) {
502
- if ( /*#__PURE__*/isValidElement(child)) {
503
- return /*#__PURE__*/_jsx(React.Fragment, {
504
- children: addIsInWrapProp(child)
505
- }, child.key || "hidden-clone-".concat(index));
506
- }
507
- return child;
508
- })
509
- })
510
- }), /*#__PURE__*/_jsx(FilterProvider, {
511
- isCollapsed: true,
512
- filterValues: filterValues,
513
- updateFilterValue: updateFilterValue,
514
- children: /*#__PURE__*/_jsx("div", {
515
- ref: moreButtonRef,
516
- style: {
517
- display: 'inline-flex'
518
- },
420
+ children: /*#__PURE__*/_jsx(FilterProvider, {
421
+ isCollapsed: true,
422
+ filterValues: filterValues,
423
+ updateFilterValue: updateFilterValue,
519
424
  children: /*#__PURE__*/_jsx(FilterWrap, {
520
425
  collapsed: true,
521
426
  icon: icon,
@@ -525,23 +430,11 @@ var ResponsiveFilterGroup = function ResponsiveFilterGroup(_ref) {
525
430
  children: /*#__PURE__*/_jsx("div", {})
526
431
  })
527
432
  })
528
- })]
529
- }), measureContainer) : null;
530
- return /*#__PURE__*/_jsxs(_Fragment, {
531
- children: [measureContent, /*#__PURE__*/_jsx("div", {
532
- ref: containerRef,
533
- style: _objectSpread({
534
- flex: '1 1 auto',
535
- minWidth: 0,
536
- overflow: 'hidden'
537
- }, style),
538
- children: /*#__PURE__*/_jsxs(Flex, {
539
- ref: innerFlexRef,
540
- gap: gap,
541
- align: "center",
542
- wrap: "nowrap",
543
- children: [unCollapsibleChildren, visibleCollapsibleChildren, renderHiddenChildren()]
544
- })
433
+ }), /*#__PURE__*/_jsx(Flex, {
434
+ gap: gap,
435
+ align: "center",
436
+ wrap: "nowrap",
437
+ children: renderChildren()
545
438
  })]
546
439
  });
547
440
  };