fui-material 2.8.19 → 2.8.21

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.
@@ -4925,6 +4925,92 @@ const FStatusBadge = ({
4925
4925
  /* @__PURE__ */ jsx("span", { children })
4926
4926
  ] });
4927
4927
  };
4928
+ function FProgressiveList({
4929
+ items,
4930
+ chunkSize = 6,
4931
+ estimatedItemHeight = 280,
4932
+ keyExtractor,
4933
+ className,
4934
+ st,
4935
+ showProgress = true,
4936
+ renderProgress,
4937
+ children,
4938
+ onLoadMore,
4939
+ hasMore = false,
4940
+ isLoadingMore = false,
4941
+ loader: loader2,
4942
+ threshold = 250
4943
+ }) {
4944
+ const totalCount = items.length;
4945
+ const [renderedCount, setRenderedCount] = useState(() => Math.min(chunkSize, totalCount));
4946
+ const sentinelRef = useRef(null);
4947
+ const prevFirstKeyRef = useRef(void 0);
4948
+ const prevTotalCountRef = useRef(totalCount);
4949
+ useEffect(() => {
4950
+ const currentFirstKey = items.length > 0 ? keyExtractor(items[0], 0) : void 0;
4951
+ const isReset = currentFirstKey !== prevFirstKeyRef.current || totalCount < prevTotalCountRef.current;
4952
+ if (isReset) {
4953
+ setRenderedCount(Math.min(chunkSize, totalCount));
4954
+ }
4955
+ prevFirstKeyRef.current = currentFirstKey;
4956
+ prevTotalCountRef.current = totalCount;
4957
+ }, [items, keyExtractor, chunkSize, totalCount]);
4958
+ useEffect(() => {
4959
+ if (renderedCount >= totalCount) return;
4960
+ const frameId = requestAnimationFrame(() => {
4961
+ setRenderedCount((prev) => Math.min(prev + chunkSize, totalCount));
4962
+ });
4963
+ return () => cancelAnimationFrame(frameId);
4964
+ }, [renderedCount, totalCount, chunkSize]);
4965
+ useEffect(() => {
4966
+ if (!onLoadMore || !hasMore || isLoadingMore) return;
4967
+ if (renderedCount < totalCount) return;
4968
+ const sentinelEl = sentinelRef.current;
4969
+ if (!sentinelEl) return;
4970
+ const observer = new IntersectionObserver(
4971
+ (entries) => {
4972
+ const [entry] = entries;
4973
+ if (entry && entry.isIntersecting) {
4974
+ onLoadMore();
4975
+ }
4976
+ },
4977
+ {
4978
+ rootMargin: `0px 0px ${threshold}px 0px`,
4979
+ threshold: 0
4980
+ }
4981
+ );
4982
+ observer.observe(sentinelEl);
4983
+ return () => {
4984
+ observer.disconnect();
4985
+ };
4986
+ }, [onLoadMore, hasMore, isLoadingMore, renderedCount, totalCount, threshold]);
4987
+ const visibleItems = items.slice(0, renderedCount);
4988
+ const itemWrapperStyle = {
4989
+ contentVisibility: "auto",
4990
+ containIntrinsicSize: `0 ${estimatedItemHeight}px`,
4991
+ marginBottom: 16
4992
+ };
4993
+ return /* @__PURE__ */ jsxs("div", { className, style: st, children: [
4994
+ visibleItems.map((item, index) => /* @__PURE__ */ jsx(
4995
+ "div",
4996
+ {
4997
+ style: itemWrapperStyle,
4998
+ children: children(item, index)
4999
+ },
5000
+ keyExtractor(item, index)
5001
+ )),
5002
+ showProgress && renderProgress && renderedCount < totalCount && /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "8px 0" }, children: renderProgress(renderedCount, totalCount) }),
5003
+ onLoadMore && hasMore && /* @__PURE__ */ jsx(
5004
+ "div",
5005
+ {
5006
+ ref: sentinelRef,
5007
+ style: { height: 1, width: "100%", pointerEvents: "none", visibility: "hidden" },
5008
+ "aria-hidden": "true"
5009
+ }
5010
+ ),
5011
+ isLoadingMore && /* @__PURE__ */ jsx("div", { style: { padding: "16px 0", textAlign: "center" }, children: loader2 ?? /* @__PURE__ */ jsx(FProgress, {}) })
5012
+ ] });
5013
+ }
4928
5014
  const FPlusIcon = React.forwardRef(({
4929
5015
  color = "primary",
4930
5016
  size = 30,
@@ -9750,9 +9836,16 @@ const useFApiQuery = (queryKey, url, config, options) => {
9750
9836
  function useFManualApiQuery(queryKey, url, initialParams, config, options) {
9751
9837
  const { apiService } = useFLibraryContext();
9752
9838
  const queryClient = useQueryClient();
9839
+ const abortControllerRef = useRef(null);
9753
9840
  const [params, setParams] = useState(initialParams);
9754
9841
  const [urlParams, setUrlParams] = useState(options == null ? void 0 : options.urlParams);
9755
9842
  const [dopUrl, setDopUrl] = useState(void 0);
9843
+ useEffect(() => {
9844
+ return () => {
9845
+ var _a;
9846
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
9847
+ };
9848
+ }, []);
9756
9849
  const {
9757
9850
  onErrorNotification = false,
9758
9851
  onErrorLog = false,
@@ -9789,6 +9882,9 @@ function useFManualApiQuery(queryKey, url, initialParams, config, options) {
9789
9882
  ...restOptions
9790
9883
  });
9791
9884
  const handleSideErrors = useCallback((error2) => {
9885
+ if (axios.isCancel(error2)) {
9886
+ return;
9887
+ }
9792
9888
  if (onErrorNotification) {
9793
9889
  fNotification({
9794
9890
  variant: "error",
@@ -9810,10 +9906,21 @@ function useFManualApiQuery(queryKey, url, initialParams, config, options) {
9810
9906
  newParams,
9811
9907
  newUrlParams,
9812
9908
  preserveParams = false,
9909
+ mergeParams = false,
9813
9910
  dopUrl: newDopUrl,
9814
9911
  preserveUrlParams = false
9815
9912
  } = {}) => {
9816
- const updatedParams = preserveParams && newParams === void 0 ? params : newParams;
9913
+ if (abortControllerRef.current) {
9914
+ abortControllerRef.current.abort();
9915
+ }
9916
+ abortControllerRef.current = new AbortController();
9917
+ const activeSignal = abortControllerRef.current.signal;
9918
+ let updatedParams;
9919
+ if (mergeParams && params && typeof params === "object" && newParams && typeof newParams === "object") {
9920
+ updatedParams = { ...params, ...newParams };
9921
+ } else {
9922
+ updatedParams = preserveParams && newParams === void 0 ? params : newParams;
9923
+ }
9817
9924
  const updatedUrlParams = newUrlParams === void 0 ? urlParams : preserveUrlParams ? { ...urlParams, ...newUrlParams } : newUrlParams;
9818
9925
  const updatedDopUrl = newDopUrl !== void 0 ? newDopUrl : dopUrl;
9819
9926
  setParams(updatedParams);
@@ -9825,7 +9932,20 @@ function useFManualApiQuery(queryKey, url, initialParams, config, options) {
9825
9932
  try {
9826
9933
  const rawResult = await queryClient.fetchQuery({
9827
9934
  queryKey: nextQueryKey,
9828
- queryFn: ({ signal }) => fetcher(updatedParams, updatedUrlParams, updatedDopUrl, signal),
9935
+ queryFn: ({ signal }) => {
9936
+ var _a;
9937
+ if (signal) {
9938
+ if (signal.aborted) {
9939
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
9940
+ } else {
9941
+ signal.addEventListener("abort", () => {
9942
+ var _a2;
9943
+ (_a2 = abortControllerRef.current) == null ? void 0 : _a2.abort();
9944
+ }, { once: true });
9945
+ }
9946
+ }
9947
+ return fetcher(updatedParams, updatedUrlParams, updatedDopUrl, activeSignal);
9948
+ },
9829
9949
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
9830
9950
  staleTime: restOptions.staleTime
9831
9951
  });
@@ -9840,6 +9960,244 @@ function useFManualApiQuery(queryKey, url, initialParams, config, options) {
9840
9960
  }, [params, urlParams, dopUrl, queryKey, fetcher, queryClient, restOptions, handleSideErrors]);
9841
9961
  return { ...query, run, params, urlParams };
9842
9962
  }
9963
+ function extractDefaultData(raw) {
9964
+ if (!raw || typeof raw !== "object") {
9965
+ return raw;
9966
+ }
9967
+ const record = raw;
9968
+ const candidate = record.result ?? record.items ?? record.content ?? record.data;
9969
+ return candidate !== void 0 ? candidate : raw;
9970
+ }
9971
+ function extractDefaultPageMeta(raw, defaultSize, currentPage) {
9972
+ if (!raw || typeof raw !== "object") return void 0;
9973
+ const record = raw;
9974
+ const p = record.page ?? record.pagination;
9975
+ if (!p || typeof p !== "object") return void 0;
9976
+ const totalItems = Number(p.totalItems ?? p.totalElements ?? p.totalCount ?? p.total ?? 0);
9977
+ const size = Number(p.size ?? p.pageSize ?? p.limit ?? defaultSize);
9978
+ const totalPages = Number(p.totalPages ?? p.pageCount ?? (size > 0 ? Math.ceil(totalItems / size) : 1));
9979
+ const number = Number(p.number ?? p.currentPage ?? p.page ?? currentPage);
9980
+ return { totalItems, size, totalPages, number };
9981
+ }
9982
+ function autoMergeAccumulatedData(prev, next) {
9983
+ if (!prev) return next;
9984
+ if (Array.isArray(next)) {
9985
+ const prevArray = Array.isArray(prev) ? prev : [];
9986
+ return [...prevArray, ...next];
9987
+ }
9988
+ if (next && typeof next === "object" && prev && typeof prev === "object") {
9989
+ const nextObj = next;
9990
+ const prevObj = prev;
9991
+ const commonArrayKeys = ["result", "items", "content", "data", "posts", "rows", "list"];
9992
+ for (const key of commonArrayKeys) {
9993
+ if (Array.isArray(nextObj[key])) {
9994
+ return {
9995
+ ...nextObj,
9996
+ [key]: [
9997
+ ...Array.isArray(prevObj[key]) ? prevObj[key] : [],
9998
+ ...nextObj[key]
9999
+ ]
10000
+ };
10001
+ }
10002
+ }
10003
+ if (nextObj.result && typeof nextObj.result === "object" && !Array.isArray(nextObj.result)) {
10004
+ const nextResult = nextObj.result;
10005
+ const prevResult = prevObj.result && typeof prevObj.result === "object" ? prevObj.result : {};
10006
+ const mergedResult = { ...nextResult };
10007
+ let hasArray = false;
10008
+ for (const subKey of Object.keys(nextResult)) {
10009
+ if (Array.isArray(nextResult[subKey])) {
10010
+ hasArray = true;
10011
+ mergedResult[subKey] = [
10012
+ ...Array.isArray(prevResult[subKey]) ? prevResult[subKey] : [],
10013
+ ...nextResult[subKey]
10014
+ ];
10015
+ }
10016
+ }
10017
+ if (hasArray) {
10018
+ return {
10019
+ ...nextObj,
10020
+ result: mergedResult
10021
+ };
10022
+ }
10023
+ }
10024
+ }
10025
+ return next;
10026
+ }
10027
+ function useFManualPagination(options) {
10028
+ const {
10029
+ queryKey,
10030
+ url,
10031
+ defaultPageSize = 20,
10032
+ initialFilters,
10033
+ method = "POST",
10034
+ config,
10035
+ mode = "pagination",
10036
+ select,
10037
+ selectPage,
10038
+ appendData,
10039
+ onErrorNotification = true,
10040
+ onErrorLog = false,
10041
+ onLoadingLog = false,
10042
+ onSuccessNotification = false,
10043
+ notificationTitle,
10044
+ notificationBody,
10045
+ loadingNotificationTitle,
10046
+ loadingNotificationBody,
10047
+ successNotificationTitle,
10048
+ successNotificationBody
10049
+ } = options;
10050
+ const [page, setPage] = useState(1);
10051
+ const [pageSize, setPageSize] = useState(defaultPageSize);
10052
+ const [accumulatedData, setAccumulatedData] = useState(void 0);
10053
+ const [isFetchingMore, setIsFetchingMore] = useState(false);
10054
+ const [isSubmitting, setIsSubmitting] = useState(false);
10055
+ const isInfinite = mode === "infinite";
10056
+ useEffect(() => {
10057
+ setPageSize(defaultPageSize);
10058
+ }, [defaultPageSize]);
10059
+ const query = useFManualApiQuery(
10060
+ queryKey,
10061
+ url,
10062
+ initialFilters ? { ...initialFilters, page: 1, size: defaultPageSize } : void 0,
10063
+ config,
10064
+ {
10065
+ method,
10066
+ onErrorNotification,
10067
+ onErrorLog,
10068
+ onLoadingLog,
10069
+ onSuccessNotification,
10070
+ notificationTitle,
10071
+ notificationBody,
10072
+ loadingNotificationTitle,
10073
+ loadingNotificationBody,
10074
+ successNotificationTitle,
10075
+ successNotificationBody
10076
+ }
10077
+ );
10078
+ const rawData = query.data;
10079
+ const pageMeta = useMemo(() => {
10080
+ if (!rawData) return void 0;
10081
+ if (selectPage) return selectPage(rawData);
10082
+ return extractDefaultPageMeta(rawData, pageSize, page);
10083
+ }, [rawData, selectPage, pageSize, page]);
10084
+ const currentExtractedData = useMemo(() => {
10085
+ if (!rawData) return void 0;
10086
+ if (select) return select(rawData);
10087
+ return extractDefaultData(rawData);
10088
+ }, [rawData, select]);
10089
+ const meta = useMemo(() => {
10090
+ if (!rawData || typeof rawData !== "object") return void 0;
10091
+ return rawData.meta;
10092
+ }, [rawData]);
10093
+ const data = isInfinite ? accumulatedData : currentExtractedData;
10094
+ const extractResult = useCallback((rawResult) => {
10095
+ if (select) return select(rawResult);
10096
+ return extractDefaultData(rawResult);
10097
+ }, [select]);
10098
+ const defaultAppend = useCallback((prev, next) => {
10099
+ if (appendData) return appendData(prev, next);
10100
+ return autoMergeAccumulatedData(prev, next);
10101
+ }, [appendData]);
10102
+ const submitFilters = useCallback(async ({
10103
+ payload,
10104
+ resetPage = true,
10105
+ dopUrl
10106
+ }) => {
10107
+ const targetPage = resetPage ? 1 : page;
10108
+ if (resetPage) {
10109
+ setPage(1);
10110
+ if (isInfinite) {
10111
+ setAccumulatedData(void 0);
10112
+ }
10113
+ }
10114
+ setIsSubmitting(true);
10115
+ try {
10116
+ const rawResponse = await query.run({
10117
+ newParams: { ...payload, page: targetPage, size: pageSize },
10118
+ dopUrl
10119
+ });
10120
+ const extracted = extractResult(rawResponse);
10121
+ if (isInfinite) {
10122
+ setAccumulatedData(extracted);
10123
+ }
10124
+ return extracted;
10125
+ } finally {
10126
+ setIsSubmitting(false);
10127
+ }
10128
+ }, [query, page, pageSize, isInfinite, extractResult]);
10129
+ const changePage = useCallback(async (newPage) => {
10130
+ if (isInfinite) {
10131
+ setIsFetchingMore(true);
10132
+ try {
10133
+ const rawResponse = await query.run({
10134
+ newParams: { page: newPage, size: pageSize },
10135
+ mergeParams: true
10136
+ });
10137
+ const extracted = extractResult(rawResponse);
10138
+ setAccumulatedData((prev) => defaultAppend(prev, extracted));
10139
+ setPage(newPage);
10140
+ return extracted;
10141
+ } finally {
10142
+ setIsFetchingMore(false);
10143
+ }
10144
+ } else {
10145
+ setPage(newPage);
10146
+ const rawResponse = await query.run({
10147
+ newParams: { page: newPage, size: pageSize },
10148
+ mergeParams: true
10149
+ });
10150
+ return extractResult(rawResponse);
10151
+ }
10152
+ }, [query, pageSize, isInfinite, extractResult, defaultAppend]);
10153
+ const hasMore = useMemo(() => {
10154
+ if (!pageMeta) return false;
10155
+ return pageMeta.number < pageMeta.totalPages;
10156
+ }, [pageMeta]);
10157
+ const loadMore = useCallback(async () => {
10158
+ if (query.isFetching || isFetchingMore || !hasMore) {
10159
+ return void 0;
10160
+ }
10161
+ const nextPage = ((pageMeta == null ? void 0 : pageMeta.number) ?? page) + 1;
10162
+ return changePage(nextPage);
10163
+ }, [query.isFetching, isFetchingMore, hasMore, pageMeta, page, changePage]);
10164
+ const paginationProps = useMemo(() => ({
10165
+ currentPage: (pageMeta == null ? void 0 : pageMeta.number) ?? page,
10166
+ totalCount: (pageMeta == null ? void 0 : pageMeta.totalItems) ?? 0,
10167
+ pageSize: (pageMeta == null ? void 0 : pageMeta.size) ?? pageSize,
10168
+ siblingCount: 1,
10169
+ onPageChange: (newPage) => {
10170
+ if (typeof newPage === "number") {
10171
+ changePage(newPage).catch(() => {
10172
+ });
10173
+ } else if (newPage === "prev") {
10174
+ changePage(Math.max(1, ((pageMeta == null ? void 0 : pageMeta.number) ?? page) - 1)).catch(() => {
10175
+ });
10176
+ } else if (newPage === "next") {
10177
+ const max = (pageMeta == null ? void 0 : pageMeta.totalPages) ?? page;
10178
+ changePage(Math.min(max, ((pageMeta == null ? void 0 : pageMeta.number) ?? page) + 1)).catch(() => {
10179
+ });
10180
+ }
10181
+ }
10182
+ }), [pageMeta, page, pageSize, changePage]);
10183
+ const isLoading = isInfinite ? isSubmitting || query.isLoading && !accumulatedData : isSubmitting || query.isLoading && !currentExtractedData;
10184
+ return {
10185
+ data,
10186
+ result: data,
10187
+ rawResponse: rawData,
10188
+ meta,
10189
+ pageMeta,
10190
+ isLoading,
10191
+ isFetching: query.isFetching,
10192
+ isFetchingMore,
10193
+ hasMore,
10194
+ error: query.error,
10195
+ submitFilters,
10196
+ changePage,
10197
+ loadMore,
10198
+ paginationProps
10199
+ };
10200
+ }
9843
10201
  const waterError = "_waterError_10t7p_1";
9844
10202
  const scene = "_scene_10t7p_12";
9845
10203
  const waves = "_waves_10t7p_18";
@@ -9985,6 +10343,7 @@ export {
9985
10343
  FPlusIcon,
9986
10344
  FPreloader,
9987
10345
  FProgress,
10346
+ FProgressiveList,
9988
10347
  FRadioButton,
9989
10348
  FReloadIcon,
9990
10349
  FSafeIcon,
@@ -10045,6 +10404,7 @@ export {
10045
10404
  useFApiQuery,
10046
10405
  useFLibraryContext,
10047
10406
  useFLibraryContextOptional,
10048
- useFManualApiQuery
10407
+ useFManualApiQuery,
10408
+ useFManualPagination
10049
10409
  };
10050
10410
  //# sourceMappingURL=f-ui-kit.es.js.map