/** Query / async lifecycle helpers — @see docs/COMPONENTS.md#query */ import type * as React from "react"; import type { InfiniteData, QueryKey, UseInfiniteQueryResult, UseMutationResult, UseQueryResult } from "@tanstack/react-query"; import type { LinkProps } from "react-router-dom"; import type { ButtonProp } from "./general.prop.js"; import type { ClassNameProp, HandlerProp } from "../vocabulary/index.js"; /** @see DataState — TanStack Query lifecycle widget (not a visual component). */ export type DataStateProp = { query: UseQueryResult; skeleton: React.ReactNode; /** Rendered when a query is disabled/unstarted (`fetchStatus: "idle"` with no data). */ prerequisite?: React.ReactNode; empty?: React.ReactNode; isEmpty?: (data: NonNullable) => boolean; errorRenderer?: (error: unknown, retry: () => void) => React.ReactNode; /** Force the Retry affordance even for non-transient causes. Retry is offered automatically for * transient/network/5xx errors regardless of this flag; default `false` for all other causes. */ showRetry?: boolean; /** Default `() => query.refetch()`. */ onRetry?: HandlerProp; /** Recovery for authentication errors (401 / expired token): renew the session or sign in again. * When provided, a 401 renders this action instead of Retry. */ onAuthError?: HandlerProp; children: (data: NonNullable) => React.ReactNode; }; type MutationLike = Pick, "isError" | "error" | "isPending">; /** @see Alert.QueryError — inline mutation error (form submit, simulator run). */ export type AlertMutationFeedbackProp = { mutation: MutationLike; onRetry?: HandlerProp; showRetry?: boolean; /** Optional inline pending slot while `mutation.isPending`. */ pending?: React.ReactNode; /** * Skip rendering when the error classifies as a validation error (`classifyQueryError` category * `"validation"`: 400/422). `true` skips every such error. When omitted, the alert is skipped only * inside a `FormRoot`/`Form` whose `errors` bag holds at least one message (the fields show it; * `FormErrors` shows unclaimed keys); an empty/absent bag still renders the alert. */ ignoreValidationErrors?: boolean; className?: ClassNameProp; }; type QueryRefetchLike = Pick, "isFetching" | "refetch">; /** @see ButtonRefetch — Button recipe wired to `query.refetch()`. */ export type ButtonRefetchProp = Omit & { query: QueryRefetchLike; label?: React.ReactNode; }; type InfiniteQueryLike = Pick, unknown>, "isPending" | "isError" | "isFetching" | "isFetchingNextPage" | "error" | "data" | "hasNextPage" | "fetchNextPage" | "refetch">; export type InfiniteQueryHelpers = { fetchNextPage: () => void; hasNextPage: boolean; isFetchingNextPage: boolean; }; /** @see InfiniteQueryState — useInfiniteQuery lifecycle + load more. */ export type InfiniteQueryStateProp = { query: InfiniteQueryLike; skeleton: React.ReactNode; empty?: React.ReactNode; flatten: (data: { pages: TPage[]; }) => TFlat; isEmpty?: (flat: TFlat) => boolean; errorRenderer?: (error: unknown, retry: () => void) => React.ReactNode; showRetry?: boolean; onRetry?: HandlerProp; /** Recovery for authentication errors (401 / expired token), shown instead of Retry. */ onAuthError?: HandlerProp; loadingMore?: React.ReactNode; /** Custom load-more footer; `false` hides footer entirely. */ loadMore?: React.ReactNode | false; /** Show default load-more button when `hasNextPage`. Default `true`. */ showLoadMore?: boolean; children: (flat: TFlat, helpers: InfiniteQueryHelpers) => React.ReactNode; }; /** @see PrefetchLink — Link + prefetchQuery on hover/focus. */ export type PrefetchLinkProp = LinkProps & { queryKey: QueryKey; queryFn: () => Promise; prefetchOn?: "hover" | "focus" | "both" | "none"; staleTime?: number; }; export {};