react-solid-flow
Version:
[SolidJS](https://www.solidjs.com/docs/latest/api#control-flow)-inspired basic control-flow components and everyday async state hook library for [React](https://reactjs.org/)
222 lines (207 loc) • 8.66 kB
TypeScript
import React, { ReactNode, ReactElement, Component, ReactPortal } from 'react';
interface ForProps<T, U extends ReactNode> {
/** Array to iterate over */
each: ReadonlyArray<T> | undefined | null;
/** RenderProp for children generation
* OR a static element displayed each.length times */
children: ReactNode | ((item: T, idx: number) => U);
/** Fallback item, displayed if *each* has zero length, or isn't an array */
fallback?: ReactNode;
}
/** Component for mapping an array into collection of ReactNode's
* Omits nullish children and provides keys if they're not specified.
*/
declare function For<T, U extends ReactNode>({ children, each, fallback, }: ForProps<T, U>): ReactElement | null;
interface ShowProps<T> {
/** predicate */
when: T | undefined | null | false;
/** content (or renderProp) to display when predicate is truthy */
children: ReactNode | ((item: NonNullable<T>) => ReactNode);
/** content to display when predicate is falsy */
fallback?: ReactNode;
}
/** Conditional rendering component */
declare function Show<T>({ fallback, ...props }: ShowProps<T>): ReactElement | null;
interface SwitchProps {
children: ReactNode;
/** content to display if no Match predicate is truthy */
fallback?: ReactNode;
}
/** Component to display one exclusive condition out of many,
* using Match component
*/
declare function Switch(props: SwitchProps): ReactElement | null;
interface MatchProps<T> {
/** predicate */
when: T | undefined | null | false;
/** content (or renderProp) to display if predicate is truthy */
children?: ReactNode | ((item: NonNullable<T>) => ReactNode);
}
/** Single branch of Switch component. */
declare function Match<T>({ when, children }: MatchProps<T>): ReactElement | null;
interface ErrorBoundaryProps {
/** renderProp (or static content) to display if error has occured */
fallback?: ReactNode | ((err: unknown, reset: () => void) => ReactNode);
/** content to display when no error was catched */
children?: ReactNode;
/** callback to call, when an error happens */
onCatch?: (error: unknown, errorInfo: unknown) => void;
}
interface ErrorBoundaryState {
error: unknown;
}
/** General ErrorBoundary component */
declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps);
state: ErrorBoundaryState;
static getDerivedStateFromError(error: unknown): {
error: unknown;
};
componentDidCatch(error: unknown, errorInfo: unknown): void;
resetError(): void;
render(): ReactNode;
}
/** This component lets you insert an arbitrary Component or tag and passes
* the props through to it.
* For example, it can be usefull when you need to conditionally render
* <a> or <span> */
declare const Dynamic: <T extends {}>(props: T & {
children?: any;
component?: string | React.ComponentClass<T, any> | React.FunctionComponent<T> | undefined;
} & React.RefAttributes<unknown>) => ReactElement | null;
interface PortalProps {
mount?: Element | DocumentFragment | string;
children?: ReactNode;
}
/** Component for rendering children outside of the Component Hierarchy root node. */
declare function Portal({ mount, ...props }: PortalProps): ReactPortal | null;
interface ResourceLike<T> {
/** Is new data currently loading */
loading?: boolean;
/** Resolved resource data for sync access */
data: Awaited<T> | undefined;
/** Rejected resource error */
error: unknown;
}
type ResourceState = "unresolved" | "pending" | "ready" | "refreshing" | "errored";
declare class Resource<T> implements ResourceLike<T> {
loading: boolean;
data: Awaited<T> | undefined;
error: unknown;
/** State name
*
* | state | data | loading | error |
* |:-----------|:-----:|:-------:|:-----:|
* | unresolved | No | No | No |
* | pending | No | Yes | No |
* | ready | Yes | No | No |
* | refreshing | Yes | Yes | No |
* | errored | No | No | Yes |
*/
state: ResourceState;
/** last resolved value
*
* This can be useful if you want to show the out-of-date data while the new
* data is loading.
*/
latest: Awaited<T> | undefined;
constructor(init?: Partial<ResourceLike<T>>, previous?: {
latest?: Awaited<T>;
});
static from<T>(data: Promise<T> | Awaited<T> | undefined, pend?: boolean): Resource<T>;
/**
* Determine resource-like state, based on its fields values.
*
* | state | data | loading | error |
* |:-----------|:-----:|:-------:|:-----:|
* | unresolved | No | No | No |
* | pending | No | Yes | No* |
* | ready | Yes | No | No |
* | refreshing | Yes | Yes | No* |
* | errored | No* | No | Yes |
*
* Values marked with * are expected to equal the specified value,
* but actually ignored, when determining the status.
*/
static getState(r: ResourceLike<unknown>): ResourceState;
}
interface AwaitProps<T> {
/** resource to wait for */
for: ResourceLike<T>;
/** renderProp (or static content) to display while loading */
fallback?: (() => ReactNode) | ReactNode;
/** renderProp (or static content) to display if resource was rejected */
catch?: ((err: unknown) => ReactNode) | ReactNode;
/** renderProp (or static content) to display when resource is resolved */
children?: ((data: Awaited<T>) => ReactNode) | ReactNode;
}
/** Component for displaying a Resource */
declare function Await<T>(props: AwaitProps<T>): ReactElement | null;
declare class AbortError extends Error {
readonly name: "AbortError";
readonly code: 20;
constructor(message?: string);
}
declare class NullishError extends Error {
readonly name: "NullishError";
}
/** State initializer.
*
* Either a value, or a function returning a value, for lazy computing.
* If state type is a function, then initializer is always lazy.
*/
type Initializer<T> = T extends Function ? () => T : T | (() => T);
type ResourceReturn<T, TArgs extends readonly unknown[]> = [
Resource<T>,
{
/** Manually set the value.
*
* If fetcher was currently pending, it's aborted.
*/
mutate: (v: Awaited<T>) => void;
/**
* Call refetch with supplied args.
*
* Fetcher opts added automatically. If fetcher was currently pending, it's aborted.
*/
refetch: (...args: TArgs) => Promise<T> | T;
/** Imperatively abort the current fetcher call.
*
* If abort is performed with no reason, or with AbortError instance, then
* the state is still considered pending/refreshing, resource.error is
* not updated, and onError callback is not called.
* Any other reason will result in erorred resource state.
*
* Resource won't be refetched untill deps change again.
*/
abort: (reason?: any) => void;
}
];
type ResourceOptions<T> = {
/** Initial value for the resource */
initialValue?: Initializer<Awaited<T>>;
/** resolve callback */
onCompleted?: (data: Awaited<T>) => void;
/** rejection callback */
onError?: (error: unknown) => void;
/** Skip first run (before params change) */
skipFirstRun?: boolean;
/** Skip calls of fetcher (can still be called manually with refresh)
*
* Can be useful if you're waiting for some of deps to be in certain state
* before calling the fetcher or if you want to trigger the fetcher only
* manually on some event.
*/
skip?: boolean;
/** Don't memoize getter, rerun it every time it changes */
skipFnMemoization?: boolean;
};
interface FetcherOpts {
/** is true, if the call to fetcher was triggered manually with refetch function,
* false otherwise */
refetching: boolean;
/** can be used to abort operations in fetcher function, i.e. passed to fetch options */
signal: AbortSignal;
}
declare function useResource<T, TArgs extends readonly any[]>(fetcher: ((...args: [...TArgs, FetcherOpts]) => Promise<T> | T) | ((...args: TArgs) => Promise<T> | T), deps?: [...TArgs], { initialValue, onCompleted, onError, skipFirstRun, skip, skipFnMemoization, }?: ResourceOptions<T>): ResourceReturn<T, TArgs>;
export { AbortError, Await, Dynamic, ErrorBoundary, For, Match, NullishError, Portal, Resource, type ResourceLike, type ResourceState, Show, Switch, useResource };