Promote useMutation to the @probo/relay package
Extract the awaitable useMutation into @probo/relay as a createUseMutation factory that delegates feedback to an injected MutationNotifier, keeping the package free of UI and i18n dependencies. compliance-portal binds it to its Base UI toast + i18next + formatError stack and imports it by explicit path (#/lib/relay/useMutation), dropping the lone intra-app barrel; a compliance-portal-scoped no-restricted-imports rule forbids react-relay's useMutation. Bring packages/relay and packages/routes into the shared ESLint scope and fix the violations that surfaced, and deprecate the legacy withQueryRef / loaderFromQueryLoader helpers. Document the shared-hook pattern and the "index.ts for package entrypoints only" rule in the relay, hooks, and app-arborescence guides. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -18,7 +18,7 @@ import { type RouteObject } from "react-router";
|
||||
export type AppRoute = Omit<RouteObject, "children"> & {
|
||||
children?: AppRoute[];
|
||||
Fallback?: ComponentType;
|
||||
}
|
||||
};
|
||||
|
||||
export function routeFromAppRoute(appRoute: AppRoute): RouteObject {
|
||||
const { Component, Fallback, children, ...rest } = appRoute;
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
export { routeFromAppRoute, type AppRoute } from "./appRoute";
|
||||
export { withQueryRef, loaderFromQueryLoader } from "./relay";
|
||||
export { type AppRoute, routeFromAppRoute } from "./appRoute";
|
||||
export { loaderFromQueryLoader, withQueryRef } from "./relay";
|
||||
|
||||
@@ -12,21 +12,31 @@
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import { useCleanup } from "@probo/hooks";
|
||||
import { type ComponentType } from "react";
|
||||
import type { EnvironmentProviderOptions, PreloadedQuery } from "react-relay";
|
||||
import { type LoaderFunction, type LoaderFunctionArgs, useLoaderData } from "react-router";
|
||||
import { type OperationType } from "relay-runtime";
|
||||
import { useCleanup } from "@probo/hooks";
|
||||
|
||||
// Infer the concrete `queryRef` type from a naked type position. Relay 21's
|
||||
// first-party types model `PreloadedQuery#variables` as `VariablesOf<TQuery>`,
|
||||
// which prevents inferring `TQuery` through it, so we infer the whole queryRef.
|
||||
/**
|
||||
* @deprecated Use a `*PageLoader` component with `useQueryLoader` +
|
||||
* `usePreloadedQuery` instead. See contrib/claude/relay.md.
|
||||
*
|
||||
* Infer the concrete `queryRef` type from a naked type position. Relay 21's
|
||||
* first-party types model `PreloadedQuery#variables` as `VariablesOf<TQuery>`,
|
||||
* which prevents inferring `TQuery` through it, so we infer the whole queryRef.
|
||||
*/
|
||||
export function withQueryRef<
|
||||
TQueryRef extends PreloadedQuery<OperationType>
|
||||
TQueryRef extends PreloadedQuery<OperationType>,
|
||||
>(
|
||||
Component: ComponentType<{ queryRef: TQueryRef }>,
|
||||
) {
|
||||
return () => {
|
||||
return function WithQueryRef() {
|
||||
// `useLoaderData` is typed `any` (default generic), and its `SerializeFrom`
|
||||
// generic would strip the `dispose` function type. Assert the loader's
|
||||
// shape so the rest of the component stays type-safe; the assertion is not
|
||||
// redundant despite the rule flagging it (the source is `any`).
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
const { queryRef, dispose } = useLoaderData() as {
|
||||
queryRef: TQueryRef;
|
||||
dispose: () => void;
|
||||
@@ -34,15 +44,19 @@ export function withQueryRef<
|
||||
|
||||
useCleanup(dispose, 1000);
|
||||
|
||||
return <Component queryRef={queryRef} />
|
||||
}
|
||||
return <Component queryRef={queryRef} />;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use a `*PageLoader` component with `useQueryLoader` +
|
||||
* `usePreloadedQuery` instead. See contrib/claude/relay.md.
|
||||
*/
|
||||
export function loaderFromQueryLoader<
|
||||
TQuery extends OperationType,
|
||||
TEnvironmentProviderOptions = EnvironmentProviderOptions
|
||||
TEnvironmentProviderOptions = EnvironmentProviderOptions,
|
||||
>(
|
||||
queryLoader: (params: Record<string, string>) => PreloadedQuery<TQuery, TEnvironmentProviderOptions>
|
||||
queryLoader: (params: Record<string, string>) => PreloadedQuery<TQuery, TEnvironmentProviderOptions>,
|
||||
): LoaderFunction {
|
||||
return ({ params }: LoaderFunctionArgs) => {
|
||||
const query = queryLoader(params as Record<string, string>);
|
||||
@@ -50,5 +64,5 @@ export function loaderFromQueryLoader<
|
||||
queryRef: query,
|
||||
dispose: query.dispose,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user