clear-react-router 1.8.5 → 1.8.7

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/README.md CHANGED
@@ -88,7 +88,7 @@ Normalizes route configuration. Extracts dynamic params, builds nested paths.
88
88
 
89
89
  ### `Link`
90
90
 
91
- Component for client-side navigation with prefetch support, active state detection, and pending state styling.
91
+ Component for client-side navigation with prefetch support, active state detection, and pending state styling. Prefetch includes lazy route component preload.
92
92
 
93
93
  | Prop | Type | Default | Description |
94
94
  |------|------|---------|-------------|
@@ -584,6 +584,14 @@ await invalidate('/posts', { withBeforeLoad: true });
584
584
  await invalidate(['/posts', '/users'], { withBeforeLoad: true });
585
585
  ```
586
586
 
587
+ #### Returns
588
+
589
+ An array of objects with the following structure:
590
+ ```ts
591
+ { path: string; data: unknown; error: unknown }
592
+ ```
593
+ Each object represents a revalidated route, where `path` is the route pathname, `data` is the revalidated loader result, and `error` is the loader error, if any.
594
+
587
595
  #### Notes
588
596
 
589
597
  * **Only routes that already have cached data are revalidated.**
@@ -1,18 +1,16 @@
1
- import { type CSSProperties, ReactNode } from 'react';
1
+ import { type CSSProperties, ReactNode, ComponentPropsWithoutRef } from 'react';
2
2
  import { RouterProps } from '../types';
3
- type LinkProps = {
3
+ type States = {
4
+ isActive: boolean;
5
+ isPending: boolean;
6
+ };
7
+ type LinkProps = Omit<ComponentPropsWithoutRef<'a'>, 'href' | 'className' | 'style'> & {
4
8
  to: string;
5
9
  children: ReactNode;
6
10
  prefetch?: RouterProps['prefetch'];
7
11
  hoverPrefetchDelay?: number;
8
- style?: CSSProperties | (({ isActive }: {
9
- isActive: boolean;
10
- isPending: boolean;
11
- }) => CSSProperties);
12
- className?: string | (({ isActive }: {
13
- isActive: boolean;
14
- isPending: boolean;
15
- }) => string);
12
+ style?: CSSProperties | ((arg: States) => CSSProperties);
13
+ className?: string | ((arg: States) => string);
16
14
  activeClassName?: string;
17
15
  pendingClassName?: string;
18
16
  onClick?(): void;
@@ -1 +1 @@
1
- export declare const useInvalidate: () => (pathList?: string | string[], options?: import("../types").InvalidateOptions) => Promise<void>;
1
+ export declare const useInvalidate: () => (pathList?: string | string[], options?: import("../types").InvalidateOptions) => Promise<import("../types").InvalidateResult[]>;
package/dist/index.js CHANGED
@@ -165,22 +165,29 @@ var import_jsx_runtime = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
165
165
  module.exports = require_react_jsx_runtime_production();
166
166
  })))();
167
167
  var createLazyComponent = (importFn, fallback) => {
168
- const LazyComp = lazy(() => importFn().then((module) => ({ default: module.default || module })));
169
- return () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Suspense, {
168
+ const load = () => importFn().then((module) => ({ default: module.default || module }));
169
+ const LazyComp = lazy(load);
170
+ const Component = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Suspense, {
170
171
  fallback: typeof fallback === "function" ? fallback() : fallback || null,
171
172
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LazyComp, {})
172
173
  });
174
+ return {
175
+ Component,
176
+ preloadElement: load
177
+ };
173
178
  };
174
179
  //#endregion
175
180
  //#region utils/utils.ts
176
181
  var isLazy = (el) => typeof el.element === "function" && el.element.toString().includes("import(");
177
182
  var parseClientRouteItem = (el, parentPattern = "") => {
178
183
  const pattern = `${parentPattern}/${el.path}`.replace(/\/+/g, "/");
179
- const resolvedElement = isLazy(el) ? createLazyComponent(el.element, el.fallback) : el.element;
184
+ const preloadElement = isLazy(el) ? createLazyComponent(el.element, el.fallback).preloadElement : void 0;
185
+ const resolvedElement = isLazy(el) ? createLazyComponent(el.element, el.fallback).Component : el.element;
180
186
  return [{
181
187
  ...el,
182
188
  pattern,
183
- element: resolvedElement
189
+ element: resolvedElement,
190
+ preloadElement
184
191
  }, ...el.children?.flatMap((child) => parseClientRouteItem(child, pattern)) ?? []];
185
192
  };
186
193
  var createRouter = (clientList) => clientList.flatMap((el) => parseClientRouteItem(el));
@@ -330,37 +337,43 @@ var createInvalidate = ({ routeItemDataState, loaderStateRef, timestampMap, curr
330
337
  beforeLoadError: error
331
338
  }));
332
339
  }
333
- await revalidateCache({
340
+ const result = await revalidateCache({
334
341
  routeItem,
335
342
  pathname
336
343
  });
337
344
  if (pathname === routePathname) currentLoaderState.setState(loaderStateRef.value);
345
+ return {
346
+ path: pathname,
347
+ ...result
348
+ };
338
349
  };
339
350
  const invalidateItem = async (pathname, options) => {
340
351
  const routeItem = findRoute(pathname);
341
- if (!routeItem) return;
352
+ if (!routeItem) return [];
342
353
  const pathnameArray = [];
343
354
  for (const [key] of timestampMap) if (comparePaths(routeItem, key)) pathnameArray.push(key);
344
- await Promise.all(pathnameArray.map((pathname) => invalidatePath(routeItem, pathname, options)));
345
- if (options?.withChildren && routeItem.children?.length) {
346
- const childPathList = routeItem.children.map((el) => el.path);
347
- await Promise.all(childPathList.map((el) => invalidateItem(`${pathname}${el}`, options)));
348
- }
355
+ const currentResults = await Promise.all(pathnameArray.map((pathname) => invalidatePath(routeItem, pathname, options)));
356
+ if (!options?.withChildren || !routeItem.children?.length) return currentResults;
357
+ const childResults = await Promise.all(routeItem.children.map((child) => invalidateItem(`${pathname}${child.path}`, options)));
358
+ return [...currentResults, ...childResults.flat()];
349
359
  };
350
360
  return async (pathList, options) => {
351
361
  const routePathname = routeItemDataState.getState().location.pathname;
352
362
  const pathnameList = Array.isArray(pathList) ? pathList : pathList ? [pathList] : [routePathname];
353
- await Promise.all(pathnameList.map((pathname) => invalidateItem(pathname, options)));
363
+ return (await Promise.all(pathnameList.map((pathname) => invalidateItem(pathname, options)))).flat();
354
364
  };
355
365
  };
356
366
  //#endregion
357
367
  //#region runtime/prefetch.ts
358
368
  var createPrefetch = (revalidateCache) => async (pathname) => {
359
369
  const item = findRoute(pathname);
360
- if (item) await revalidateCache({
361
- routeItem: item,
362
- pathname
363
- });
370
+ if (item) {
371
+ await item.preloadElement?.();
372
+ await revalidateCache({
373
+ routeItem: item,
374
+ pathname
375
+ });
376
+ }
364
377
  };
365
378
  //#endregion
366
379
  //#region utils/revalidateCache.ts
@@ -393,10 +406,7 @@ var createRevalidateCache = (routerState) => {
393
406
  if (isCacheItemFresh({
394
407
  routeItem,
395
408
  pathname
396
- })) {
397
- loaderStateRef.set(loaderMapRef[pathname]);
398
- return;
399
- }
409
+ })) loaderStateRef.set(loaderMapRef[pathname]);
400
410
  const promise = (async () => {
401
411
  if (!routeItem?.loader) return;
402
412
  try {
@@ -415,6 +425,10 @@ var createRevalidateCache = (routerState) => {
415
425
  loaderError: null
416
426
  }));
417
427
  loaderMapRef[pathname] = loaderStateRef.value;
428
+ return {
429
+ data: result,
430
+ error: null
431
+ };
418
432
  } catch (error) {
419
433
  const retry = getRetry(routeItem);
420
434
  if (retry && retry.count > retried) {
@@ -424,11 +438,21 @@ var createRevalidateCache = (routerState) => {
424
438
  routeItem,
425
439
  pathname
426
440
  }, retried + 1);
427
- } else loaderStateRef.set((prev) => ({
428
- ...prev,
429
- data: null,
430
- loaderError: error
431
- }));
441
+ return {
442
+ data: null,
443
+ error
444
+ };
445
+ } else {
446
+ loaderStateRef.set((prev) => ({
447
+ ...prev,
448
+ data: null,
449
+ loaderError: error
450
+ }));
451
+ return {
452
+ data: null,
453
+ error
454
+ };
455
+ }
432
456
  } finally {
433
457
  loadingPromises.delete(pathname);
434
458
  }
@@ -1,2 +1,2 @@
1
- import { type InvalidateOptions, RevalidateCache, RouterState } from '../types';
2
- export declare const createInvalidate: ({ routeItemDataState, loaderStateRef, timestampMap, currentLoaderState, contextState }: RouterState, revalidateCache: RevalidateCache) => (pathList?: string | string[], options?: InvalidateOptions) => Promise<void>;
1
+ import { type InvalidateOptions, InvalidateResult, RevalidateCache, RouterState } from '../types';
2
+ export declare const createInvalidate: ({ routeItemDataState, loaderStateRef, timestampMap, currentLoaderState, contextState }: RouterState, revalidateCache: RevalidateCache) => (pathList?: string | string[], options?: InvalidateOptions) => Promise<InvalidateResult[]>;
package/dist/types.d.ts CHANGED
@@ -34,7 +34,7 @@ export type ClientRouteItem = {
34
34
  actions?: (arg: {
35
35
  context: Record<string, unknown>;
36
36
  params: Record<string, string>;
37
- invalidate: (path?: string) => Promise<void>;
37
+ invalidate: (path?: string) => Promise<InvalidateResult[]>;
38
38
  setContext: Dispatch<SetStateAction<Record<string, unknown>>>;
39
39
  }) => Record<string, (arg: FormData) => Promise<unknown> | Promise<void> | void | unknown>;
40
40
  };
@@ -42,6 +42,9 @@ export type RouteItem = ClientRouteItem & {
42
42
  element: RenderElement;
43
43
  pattern: string;
44
44
  cacheTimestamp?: number;
45
+ preloadElement?(): Promise<{
46
+ default: ComponentType<unknown>;
47
+ }>;
45
48
  };
46
49
  export type Location = {
47
50
  pathname: string;
@@ -110,7 +113,7 @@ export type RouterType = {
110
113
  state: Omit<RouterState, 'loaderStateRef' | 'timestampMap'>;
111
114
  runtime: {
112
115
  navigate(arg: Location): Promise<void>;
113
- invalidate(pathList?: string | string[], options?: InvalidateOptions): Promise<void>;
116
+ invalidate(pathList?: string | string[], options?: InvalidateOptions): Promise<InvalidateResult[]>;
114
117
  prefetch(pathname: string): Promise<void>;
115
118
  };
116
119
  hooks: {
@@ -128,7 +131,7 @@ export type RouterType = {
128
131
  useNavigate: () => (arg: Location | string | -1) => Promise<void>;
129
132
  useGetAction: (actionKey: string) => {
130
133
  currentAction: (arg: FormData) => Promise<unknown> | Promise<void> | void | unknown;
131
- invalidate: (pathList?: string | string[], options?: InvalidateOptions) => Promise<void>;
134
+ invalidate: (pathList?: string | string[], options?: InvalidateOptions) => Promise<InvalidateResult[]>;
132
135
  };
133
136
  useRestoreScroll: () => () => void;
134
137
  useAction: (action: string, options?: Options) => (arg: FormData) => Promise<void>;
@@ -138,9 +141,16 @@ export type InvalidateOptions = {
138
141
  withChildren?: boolean;
139
142
  withBeforeLoad?: boolean;
140
143
  };
141
- export type RevalidateCache = ({ routeItem, pathname }: RevalidateCacheArgs) => Promise<unknown> | undefined;
144
+ export type RevalidateCache = ({ routeItem, pathname, }: RevalidateCacheArgs) => Promise<{
145
+ data: unknown;
146
+ error: unknown;
147
+ }>;
142
148
  export type Options = Partial<{
143
149
  onSuccess: (args: unknown) => void;
144
150
  onError: (args: unknown) => void;
145
151
  }> | undefined;
152
+ export type InvalidateResult = {
153
+ path: string;
154
+ data: unknown;
155
+ };
146
156
  export {};
@@ -1,4 +1,9 @@
1
1
  import { type ComponentType, type ReactElement } from 'react';
2
2
  export declare const createLazyComponent: (importFn: () => Promise<{
3
3
  default: ComponentType<unknown>;
4
- }>, fallback?: ReactElement | (() => ReactElement)) => (() => ReactElement);
4
+ }>, fallback?: ReactElement | (() => ReactElement)) => {
5
+ Component: () => import("react/jsx-runtime").JSX.Element;
6
+ preloadElement: () => Promise<{
7
+ default: ComponentType<unknown>;
8
+ }>;
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clear-react-router",
3
- "version": "1.8.5",
3
+ "version": "1.8.7",
4
4
  "description": "A lightweight, type-safe routing library for React applications",
5
5
  "author": "Andrew Bubnov",
6
6
  "scripts": {