@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.
- package/dist/design.min.js +1 -1
- package/es/alert/index.d.ts +1 -1
- package/es/alert/index.js +4 -2
- package/es/filter/components/CountNumber.js +2 -1
- package/es/filter/components/FilterButton.d.ts +2 -0
- package/es/filter/components/FilterButton.js +6 -3
- package/es/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.d.ts +20 -0
- package/es/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.js +101 -0
- package/es/filter/components/FilterCascader/components/CascaderOption/OptionItem.d.ts +13 -0
- package/es/filter/components/FilterCascader/components/CascaderOption/OptionItem.js +44 -0
- package/es/filter/components/FilterCascader/components/FlatCascaderContent/index.d.ts +16 -0
- package/es/filter/components/FilterCascader/components/FlatCascaderContent/index.js +64 -0
- package/es/filter/components/FilterCascader/components/NormalCascaderContent.d.ts +24 -0
- package/es/filter/components/FilterCascader/components/NormalCascaderContent.js +284 -0
- package/es/filter/components/FilterCascader/constants.d.ts +7 -0
- package/es/filter/components/FilterCascader/constants.js +8 -0
- package/es/filter/components/FilterCascader/hooks/useCascaderCallbacks.d.ts +12 -0
- package/es/filter/components/FilterCascader/hooks/useCascaderCallbacks.js +101 -0
- package/es/filter/components/FilterCascader/hooks/useCascaderLabels.d.ts +9 -0
- package/es/filter/components/FilterCascader/hooks/useCascaderLabels.js +50 -0
- package/es/filter/components/FilterCascader/hooks/useNormalizedValue.d.ts +7 -0
- package/es/filter/components/FilterCascader/hooks/useNormalizedValue.js +53 -0
- package/es/filter/components/FilterCascader/index.d.ts +5 -0
- package/es/filter/components/FilterCascader/index.js +317 -0
- package/es/filter/components/FilterCascader/types.d.ts +56 -0
- package/es/filter/components/FilterCascader/types.js +1 -0
- package/es/filter/components/FilterCascader/utils/countUtils.d.ts +13 -0
- package/es/filter/components/FilterCascader/utils/countUtils.js +48 -0
- package/es/filter/components/FilterCascader/utils/pathUtils.d.ts +17 -0
- package/es/filter/components/FilterCascader/utils/pathUtils.js +91 -0
- package/es/filter/components/FilterCheckbox.js +29 -7
- package/es/filter/components/FilterWrap.js +30 -1
- package/es/filter/components/ResponsiveFilterGroup.js +252 -359
- package/es/filter/index.d.ts +1 -1
- package/es/filter/index.js +11 -7
- package/es/filter/style/index.js +9 -2
- package/es/filter/type.d.ts +5 -0
- package/es/table/index.d.ts +2 -2
- package/lib/alert/index.d.ts +1 -1
- package/lib/alert/index.js +3 -1
- package/lib/filter/components/CountNumber.js +2 -1
- package/lib/filter/components/FilterButton.d.ts +2 -0
- package/lib/filter/components/FilterButton.js +4 -2
- package/lib/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.d.ts +20 -0
- package/lib/filter/components/FilterCascader/components/CascaderOption/OptionCheckbox.js +91 -0
- package/lib/filter/components/FilterCascader/components/CascaderOption/OptionItem.d.ts +13 -0
- package/lib/filter/components/FilterCascader/components/CascaderOption/OptionItem.js +51 -0
- package/lib/filter/components/FilterCascader/components/FlatCascaderContent/index.d.ts +16 -0
- package/lib/filter/components/FilterCascader/components/FlatCascaderContent/index.js +70 -0
- package/lib/filter/components/FilterCascader/components/NormalCascaderContent.d.ts +24 -0
- package/lib/filter/components/FilterCascader/components/NormalCascaderContent.js +263 -0
- package/lib/filter/components/FilterCascader/constants.d.ts +7 -0
- package/lib/filter/components/FilterCascader/constants.js +14 -0
- package/lib/filter/components/FilterCascader/hooks/useCascaderCallbacks.d.ts +12 -0
- package/lib/filter/components/FilterCascader/hooks/useCascaderCallbacks.js +81 -0
- package/lib/filter/components/FilterCascader/hooks/useCascaderLabels.d.ts +9 -0
- package/lib/filter/components/FilterCascader/hooks/useCascaderLabels.js +56 -0
- package/lib/filter/components/FilterCascader/hooks/useNormalizedValue.d.ts +7 -0
- package/lib/filter/components/FilterCascader/hooks/useNormalizedValue.js +48 -0
- package/lib/filter/components/FilterCascader/index.d.ts +5 -0
- package/lib/filter/components/FilterCascader/index.js +298 -0
- package/lib/filter/components/FilterCascader/types.d.ts +56 -0
- package/lib/filter/components/FilterCascader/types.js +5 -0
- package/lib/filter/components/FilterCascader/utils/countUtils.d.ts +13 -0
- package/lib/filter/components/FilterCascader/utils/countUtils.js +49 -0
- package/lib/filter/components/FilterCascader/utils/pathUtils.d.ts +17 -0
- package/lib/filter/components/FilterCascader/utils/pathUtils.js +56 -0
- package/lib/filter/components/FilterCheckbox.js +29 -7
- package/lib/filter/components/FilterWrap.js +28 -1
- package/lib/filter/components/ResponsiveFilterGroup.js +214 -340
- package/lib/filter/index.d.ts +1 -1
- package/lib/filter/index.js +11 -7
- package/lib/filter/style/index.js +10 -1
- package/lib/filter/type.d.ts +5 -0
- package/package.json +3 -3
- package/es/filter/components/FilterCascader.d.ts +0 -31
- package/es/filter/components/FilterCascader.js +0 -529
- package/lib/filter/components/FilterCascader.d.ts +0 -31
- 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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
107
|
-
const
|
|
108
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
//
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
206
|
-
|
|
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
|
-
//
|
|
147
|
+
// Effect 1: 测量模式下,读取所有子元素宽度并计算 visibleCount
|
|
216
148
|
(0, _react.useLayoutEffect)(() => {
|
|
217
|
-
if (
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
|
254
|
-
|
|
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
|
-
|
|
257
|
-
return () =>
|
|
258
|
-
|
|
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
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
348
|
-
|
|
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
|
-
|
|
354
|
-
|
|
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
|
-
//
|
|
244
|
+
// --- 渲染 FilterWrap(收起的筛选项) ---
|
|
368
245
|
const renderHiddenChildren = () => {
|
|
369
|
-
if (
|
|
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:
|
|
399
|
-
if ( /*#__PURE__*/(0, _react.isValidElement)(child)) {
|
|
400
|
-
|
|
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:
|
|
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
|
-
//
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
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
|
|
322
|
+
display
|
|
427
323
|
},
|
|
428
324
|
children: child
|
|
429
|
-
}
|
|
430
|
-
})
|
|
431
|
-
|
|
432
|
-
|
|
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
|
-
|
|
435
|
-
|
|
436
|
-
|
|
354
|
+
position: 'absolute',
|
|
355
|
+
visibility: 'hidden',
|
|
356
|
+
pointerEvents: 'none',
|
|
357
|
+
top: -9999,
|
|
358
|
+
left: -9999,
|
|
359
|
+
display: 'inline-flex'
|
|
437
360
|
},
|
|
438
|
-
children:
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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
|
};
|