fui-material 2.8.22 → 2.8.23
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/f-ui-kit.es.js +181 -25
- package/dist/f-ui-kit.es.js.map +1 -1
- package/dist/f-ui-kit.umd.js +2 -2
- package/dist/f-ui-kit.umd.js.map +1 -1
- package/dist/types/material/FProgressiveList/FProgressiveList.d.ts +1 -1
- package/dist/types/material/FProgressiveList/types.d.ts +11 -0
- package/package.json +1 -1
package/dist/f-ui-kit.es.js
CHANGED
|
@@ -4925,6 +4925,21 @@ const FStatusBadge = ({
|
|
|
4925
4925
|
/* @__PURE__ */ jsx("span", { children })
|
|
4926
4926
|
] });
|
|
4927
4927
|
};
|
|
4928
|
+
function findOffsetIndex(offsets, targetOffset) {
|
|
4929
|
+
let low = 0;
|
|
4930
|
+
let high = offsets.length - 2;
|
|
4931
|
+
let result = 0;
|
|
4932
|
+
while (low <= high) {
|
|
4933
|
+
const mid = low + high >> 1;
|
|
4934
|
+
if (offsets[mid] <= targetOffset) {
|
|
4935
|
+
result = mid;
|
|
4936
|
+
low = mid + 1;
|
|
4937
|
+
} else {
|
|
4938
|
+
high = mid - 1;
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4941
|
+
return result;
|
|
4942
|
+
}
|
|
4928
4943
|
function FProgressiveList({
|
|
4929
4944
|
items,
|
|
4930
4945
|
chunkSize = 6,
|
|
@@ -4939,14 +4954,18 @@ function FProgressiveList({
|
|
|
4939
4954
|
hasMore = false,
|
|
4940
4955
|
isLoadingMore = false,
|
|
4941
4956
|
loader: loader2,
|
|
4942
|
-
threshold = 250
|
|
4957
|
+
threshold = 250,
|
|
4958
|
+
virtualize = false,
|
|
4959
|
+
overscan = 2
|
|
4943
4960
|
}) {
|
|
4944
4961
|
const totalCount = items.length;
|
|
4962
|
+
const containerRef = useRef(null);
|
|
4945
4963
|
const [renderedCount, setRenderedCount] = useState(() => Math.min(chunkSize, totalCount));
|
|
4946
4964
|
const sentinelRef = useRef(null);
|
|
4947
4965
|
const prevFirstKeyRef = useRef(void 0);
|
|
4948
4966
|
const prevTotalCountRef = useRef(totalCount);
|
|
4949
4967
|
useEffect(() => {
|
|
4968
|
+
if (virtualize) return;
|
|
4950
4969
|
const currentFirstKey = items.length > 0 ? keyExtractor(items[0], 0) : void 0;
|
|
4951
4970
|
const isReset = currentFirstKey !== prevFirstKeyRef.current || totalCount < prevTotalCountRef.current;
|
|
4952
4971
|
if (isReset) {
|
|
@@ -4954,17 +4973,119 @@ function FProgressiveList({
|
|
|
4954
4973
|
}
|
|
4955
4974
|
prevFirstKeyRef.current = currentFirstKey;
|
|
4956
4975
|
prevTotalCountRef.current = totalCount;
|
|
4957
|
-
}, [items, keyExtractor, chunkSize, totalCount]);
|
|
4976
|
+
}, [items, keyExtractor, chunkSize, totalCount, virtualize]);
|
|
4958
4977
|
useEffect(() => {
|
|
4978
|
+
if (virtualize) return;
|
|
4959
4979
|
if (renderedCount >= totalCount) return;
|
|
4960
4980
|
const frameId = requestAnimationFrame(() => {
|
|
4961
4981
|
setRenderedCount((prev) => Math.min(prev + chunkSize, totalCount));
|
|
4962
4982
|
});
|
|
4963
4983
|
return () => cancelAnimationFrame(frameId);
|
|
4964
|
-
}, [renderedCount, totalCount, chunkSize]);
|
|
4984
|
+
}, [renderedCount, totalCount, chunkSize, virtualize]);
|
|
4985
|
+
const measuredHeights = useRef(/* @__PURE__ */ new Map());
|
|
4986
|
+
const [measureVersion, setMeasureVersion] = useState(0);
|
|
4987
|
+
const resizeObserverRef = useRef(null);
|
|
4988
|
+
useEffect(() => {
|
|
4989
|
+
if (!virtualize) return;
|
|
4990
|
+
const currentFirstKey = items.length > 0 ? keyExtractor(items[0], 0) : void 0;
|
|
4991
|
+
if (currentFirstKey !== prevFirstKeyRef.current || totalCount < prevTotalCountRef.current) {
|
|
4992
|
+
measuredHeights.current.clear();
|
|
4993
|
+
setMeasureVersion((v) => v + 1);
|
|
4994
|
+
}
|
|
4995
|
+
prevFirstKeyRef.current = currentFirstKey;
|
|
4996
|
+
prevTotalCountRef.current = totalCount;
|
|
4997
|
+
}, [items, keyExtractor, totalCount, virtualize]);
|
|
4998
|
+
useEffect(() => {
|
|
4999
|
+
if (!virtualize) return;
|
|
5000
|
+
const ro = new ResizeObserver((entries) => {
|
|
5001
|
+
var _a, _b;
|
|
5002
|
+
let changed = false;
|
|
5003
|
+
for (const entry of entries) {
|
|
5004
|
+
const indexAttr = entry.target.getAttribute("data-virtual-index");
|
|
5005
|
+
if (indexAttr !== null) {
|
|
5006
|
+
const index = Number(indexAttr);
|
|
5007
|
+
const height = ((_b = (_a = entry.borderBoxSize) == null ? void 0 : _a[0]) == null ? void 0 : _b.blockSize) ?? entry.contentRect.height;
|
|
5008
|
+
const prevHeight = measuredHeights.current.get(index);
|
|
5009
|
+
if (height > 0 && (!prevHeight || Math.abs(prevHeight - height) > 2)) {
|
|
5010
|
+
measuredHeights.current.set(index, height);
|
|
5011
|
+
changed = true;
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
if (changed) {
|
|
5016
|
+
setMeasureVersion((v) => v + 1);
|
|
5017
|
+
}
|
|
5018
|
+
});
|
|
5019
|
+
resizeObserverRef.current = ro;
|
|
5020
|
+
return () => ro.disconnect();
|
|
5021
|
+
}, [virtualize]);
|
|
5022
|
+
const offsets = useMemo(() => {
|
|
5023
|
+
if (!virtualize) return new Float64Array(0);
|
|
5024
|
+
const arr = new Float64Array(totalCount + 1);
|
|
5025
|
+
let sum = 0;
|
|
5026
|
+
for (let i = 0; i < totalCount; i++) {
|
|
5027
|
+
arr[i] = sum;
|
|
5028
|
+
const h = measuredHeights.current.get(i) ?? estimatedItemHeight;
|
|
5029
|
+
sum += h;
|
|
5030
|
+
}
|
|
5031
|
+
arr[totalCount] = sum;
|
|
5032
|
+
return arr;
|
|
5033
|
+
}, [totalCount, estimatedItemHeight, virtualize, measureVersion]);
|
|
5034
|
+
const [scrollState, setScrollState] = useState(() => ({
|
|
5035
|
+
scrollTop: 0,
|
|
5036
|
+
viewportHeight: typeof window !== "undefined" ? window.innerHeight : 800
|
|
5037
|
+
}));
|
|
5038
|
+
useEffect(() => {
|
|
5039
|
+
if (!virtualize) return;
|
|
5040
|
+
let rafId = null;
|
|
5041
|
+
const handleScroll = () => {
|
|
5042
|
+
if (rafId !== null) return;
|
|
5043
|
+
rafId = requestAnimationFrame(() => {
|
|
5044
|
+
rafId = null;
|
|
5045
|
+
if (!containerRef.current) return;
|
|
5046
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
5047
|
+
const scrollTop = Math.max(0, -rect.top);
|
|
5048
|
+
const viewportHeight = window.innerHeight;
|
|
5049
|
+
setScrollState((prev) => {
|
|
5050
|
+
if (Math.abs(prev.scrollTop - scrollTop) > 30 || prev.viewportHeight !== viewportHeight) {
|
|
5051
|
+
return { scrollTop, viewportHeight };
|
|
5052
|
+
}
|
|
5053
|
+
return prev;
|
|
5054
|
+
});
|
|
5055
|
+
});
|
|
5056
|
+
};
|
|
5057
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
5058
|
+
window.addEventListener("resize", handleScroll, { passive: true });
|
|
5059
|
+
handleScroll();
|
|
5060
|
+
return () => {
|
|
5061
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
5062
|
+
window.removeEventListener("scroll", handleScroll);
|
|
5063
|
+
window.removeEventListener("resize", handleScroll);
|
|
5064
|
+
};
|
|
5065
|
+
}, [virtualize]);
|
|
5066
|
+
const { startIndex, endIndex, topSpacerHeight, bottomSpacerHeight } = useMemo(() => {
|
|
5067
|
+
if (!virtualize || totalCount === 0 || offsets.length <= 1) {
|
|
5068
|
+
return { startIndex: 0, endIndex: 0, topSpacerHeight: 0, bottomSpacerHeight: 0 };
|
|
5069
|
+
}
|
|
5070
|
+
const visibleTop = scrollState.scrollTop;
|
|
5071
|
+
const visibleBottom = scrollState.scrollTop + scrollState.viewportHeight;
|
|
5072
|
+
const rawStartIndex = findOffsetIndex(offsets, visibleTop);
|
|
5073
|
+
const rawEndIndex = findOffsetIndex(offsets, visibleBottom);
|
|
5074
|
+
const sIdx = Math.max(0, rawStartIndex - overscan);
|
|
5075
|
+
const eIdx = Math.min(totalCount - 1, rawEndIndex + overscan);
|
|
5076
|
+
const topHeight = offsets[sIdx] || 0;
|
|
5077
|
+
const totalHeight = offsets[totalCount] || 0;
|
|
5078
|
+
const bottomHeight = Math.max(0, totalHeight - (offsets[eIdx + 1] || totalHeight));
|
|
5079
|
+
return {
|
|
5080
|
+
startIndex: sIdx,
|
|
5081
|
+
endIndex: eIdx,
|
|
5082
|
+
topSpacerHeight: topHeight,
|
|
5083
|
+
bottomSpacerHeight: bottomHeight
|
|
5084
|
+
};
|
|
5085
|
+
}, [virtualize, totalCount, offsets, scrollState, overscan]);
|
|
4965
5086
|
useEffect(() => {
|
|
4966
5087
|
if (!onLoadMore || !hasMore || isLoadingMore) return;
|
|
4967
|
-
if (renderedCount < totalCount) return;
|
|
5088
|
+
if (!virtualize && renderedCount < totalCount) return;
|
|
4968
5089
|
const sentinelEl = sentinelRef.current;
|
|
4969
5090
|
if (!sentinelEl) return;
|
|
4970
5091
|
const observer = new IntersectionObserver(
|
|
@@ -4980,26 +5101,56 @@ function FProgressiveList({
|
|
|
4980
5101
|
}
|
|
4981
5102
|
);
|
|
4982
5103
|
observer.observe(sentinelEl);
|
|
4983
|
-
return () =>
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
5104
|
+
return () => observer.disconnect();
|
|
5105
|
+
}, [onLoadMore, hasMore, isLoadingMore, renderedCount, totalCount, threshold, virtualize]);
|
|
5106
|
+
useEffect(() => {
|
|
5107
|
+
if (!virtualize || !onLoadMore || !hasMore || isLoadingMore) return;
|
|
5108
|
+
if (totalCount > 0 && endIndex >= totalCount - 1 - overscan) {
|
|
5109
|
+
onLoadMore();
|
|
5110
|
+
}
|
|
5111
|
+
}, [virtualize, endIndex, totalCount, overscan, onLoadMore, hasMore, isLoadingMore]);
|
|
5112
|
+
const setItemRef = useCallback((el) => {
|
|
5113
|
+
if (el && resizeObserverRef.current) {
|
|
5114
|
+
resizeObserverRef.current.observe(el);
|
|
5115
|
+
}
|
|
5116
|
+
}, []);
|
|
4988
5117
|
const itemWrapperStyle = {
|
|
4989
|
-
contentVisibility: "auto",
|
|
4990
|
-
containIntrinsicSize: `0 ${estimatedItemHeight}px`,
|
|
5118
|
+
contentVisibility: virtualize ? void 0 : "auto",
|
|
5119
|
+
containIntrinsicSize: virtualize ? void 0 : `0 ${estimatedItemHeight}px`,
|
|
4991
5120
|
marginBottom: 16
|
|
4992
5121
|
};
|
|
4993
|
-
return /* @__PURE__ */ jsxs("div", { className, style: st, children: [
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
{
|
|
4997
|
-
style:
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5122
|
+
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className, style: st, children: [
|
|
5123
|
+
virtualize ? (
|
|
5124
|
+
// --- РЕНДЕР С ВИРТУАЛЬНЫМ ОКНОМ ---
|
|
5125
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5126
|
+
topSpacerHeight > 0 && /* @__PURE__ */ jsx("div", { style: { height: topSpacerHeight, width: "100%" }, "aria-hidden": "true" }),
|
|
5127
|
+
items.slice(startIndex, endIndex + 1).map((item, localIndex) => {
|
|
5128
|
+
const globalIndex = startIndex + localIndex;
|
|
5129
|
+
return /* @__PURE__ */ jsx(
|
|
5130
|
+
"div",
|
|
5131
|
+
{
|
|
5132
|
+
ref: setItemRef,
|
|
5133
|
+
"data-virtual-index": globalIndex,
|
|
5134
|
+
style: itemWrapperStyle,
|
|
5135
|
+
children: children(item, globalIndex)
|
|
5136
|
+
},
|
|
5137
|
+
keyExtractor(item, globalIndex)
|
|
5138
|
+
);
|
|
5139
|
+
}),
|
|
5140
|
+
bottomSpacerHeight > 0 && /* @__PURE__ */ jsx("div", { style: { height: bottomSpacerHeight, width: "100%" }, "aria-hidden": "true" })
|
|
5141
|
+
] })
|
|
5142
|
+
) : (
|
|
5143
|
+
// --- СТАНДАРТНЫЙ ПРОГРЕССИВНЫЙ РЕНДЕР ---
|
|
5144
|
+
items.slice(0, renderedCount).map((item, index) => /* @__PURE__ */ jsx(
|
|
5145
|
+
"div",
|
|
5146
|
+
{
|
|
5147
|
+
style: itemWrapperStyle,
|
|
5148
|
+
children: children(item, index)
|
|
5149
|
+
},
|
|
5150
|
+
keyExtractor(item, index)
|
|
5151
|
+
))
|
|
5152
|
+
),
|
|
5153
|
+
!virtualize && showProgress && renderProgress && renderedCount < totalCount && /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "8px 0" }, children: renderProgress(renderedCount, totalCount) }),
|
|
5003
5154
|
onLoadMore && hasMore && /* @__PURE__ */ jsx(
|
|
5004
5155
|
"div",
|
|
5005
5156
|
{
|
|
@@ -10104,9 +10255,11 @@ function useFManualPagination(options) {
|
|
|
10104
10255
|
resetPage = true,
|
|
10105
10256
|
dopUrl
|
|
10106
10257
|
}) => {
|
|
10107
|
-
const
|
|
10258
|
+
const payloadObj = payload && typeof payload === "object" ? payload : void 0;
|
|
10259
|
+
const targetPage = payloadObj && typeof payloadObj.page === "number" ? payloadObj.page : resetPage ? 1 : page;
|
|
10260
|
+
const targetSize = payloadObj && typeof payloadObj.size === "number" ? payloadObj.size : pageSize || defaultPageSize || 20;
|
|
10108
10261
|
if (resetPage) {
|
|
10109
|
-
setPage(
|
|
10262
|
+
setPage(targetPage);
|
|
10110
10263
|
if (isInfinite) {
|
|
10111
10264
|
setAccumulatedData(void 0);
|
|
10112
10265
|
}
|
|
@@ -10114,7 +10267,8 @@ function useFManualPagination(options) {
|
|
|
10114
10267
|
setIsSubmitting(true);
|
|
10115
10268
|
try {
|
|
10116
10269
|
const rawResponse = await query.run({
|
|
10117
|
-
newParams: { ...payload, page: targetPage, size:
|
|
10270
|
+
newParams: { ...payload, page: targetPage, size: targetSize },
|
|
10271
|
+
newUrlParams: { page: targetPage, size: targetSize },
|
|
10118
10272
|
dopUrl
|
|
10119
10273
|
});
|
|
10120
10274
|
const extracted = extractResult(rawResponse);
|
|
@@ -10125,13 +10279,14 @@ function useFManualPagination(options) {
|
|
|
10125
10279
|
} finally {
|
|
10126
10280
|
setIsSubmitting(false);
|
|
10127
10281
|
}
|
|
10128
|
-
}, [query, page, pageSize, isInfinite, extractResult]);
|
|
10282
|
+
}, [query, page, pageSize, defaultPageSize, isInfinite, extractResult]);
|
|
10129
10283
|
const changePage = useCallback(async (newPage) => {
|
|
10130
10284
|
if (isInfinite) {
|
|
10131
10285
|
setIsFetchingMore(true);
|
|
10132
10286
|
try {
|
|
10133
10287
|
const rawResponse = await query.run({
|
|
10134
10288
|
newParams: { page: newPage, size: pageSize },
|
|
10289
|
+
newUrlParams: { page: newPage, size: pageSize },
|
|
10135
10290
|
mergeParams: true
|
|
10136
10291
|
});
|
|
10137
10292
|
const extracted = extractResult(rawResponse);
|
|
@@ -10145,6 +10300,7 @@ function useFManualPagination(options) {
|
|
|
10145
10300
|
setPage(newPage);
|
|
10146
10301
|
const rawResponse = await query.run({
|
|
10147
10302
|
newParams: { page: newPage, size: pageSize },
|
|
10303
|
+
newUrlParams: { page: newPage, size: pageSize },
|
|
10148
10304
|
mergeParams: true
|
|
10149
10305
|
});
|
|
10150
10306
|
return extractResult(rawResponse);
|