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