clear-react-router 1.6.8 → 1.7.0
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
|
@@ -272,7 +272,7 @@ Actions can be executed declaratively with `<Form />` or imperatively with `useA
|
|
|
272
272
|
import { Form, useFormContext } from '../clear-router';
|
|
273
273
|
|
|
274
274
|
const SubmitButton = () => {
|
|
275
|
-
const {
|
|
275
|
+
const {isSubmitting} = useFormContext()
|
|
276
276
|
return <button disabled={isSubmitting} type='submit'>Save</button>
|
|
277
277
|
}
|
|
278
278
|
|
|
@@ -305,6 +305,13 @@ After a successful action:
|
|
|
305
305
|
|
|
306
306
|
`useAction` provides direct access to a route action without rendering a `<Form />`.
|
|
307
307
|
|
|
308
|
+
### Arguments
|
|
309
|
+
|
|
310
|
+
| Argument | Type | Description |
|
|
311
|
+
|----------|------|-------------|
|
|
312
|
+
| `action` | `string` | Name of the route action to execute. Must match a key returned from the route's `actions` configuration. |
|
|
313
|
+
| `options` | `{ onSuccess?, onError? }` | Optional callbacks invoked after the action succeeds or fails. |
|
|
314
|
+
|
|
308
315
|
```tsx
|
|
309
316
|
const save = useAction('save');
|
|
310
317
|
|
|
@@ -508,29 +515,6 @@ useEffect(() => {
|
|
|
508
515
|
}, [state, process, reset]);
|
|
509
516
|
```
|
|
510
517
|
|
|
511
|
-
### `useBeforeUnload(callback?)`
|
|
512
|
-
|
|
513
|
-
Executes a callback when the page is about to be closed or reloaded. Perfect for auto-saving data at the last moment.
|
|
514
|
-
|
|
515
|
-
**Parameters:**
|
|
516
|
-
|
|
517
|
-
| Parameter | Type | Description |
|
|
518
|
-
|-----------|------|-------------|
|
|
519
|
-
| `callback` | `() => void \| undefined` | Function to execute before page unload (e.g., auto-save) |
|
|
520
|
-
|
|
521
|
-
**Note:** This hook does not show a browser confirmation dialog. It silently executes the callback, allowing you to save user data in the background before the page closes.
|
|
522
|
-
|
|
523
|
-
```tsx
|
|
524
|
-
const [text, setText] = useState('');
|
|
525
|
-
const onSave = useCallback(() => {
|
|
526
|
-
localStorage.setItem('draft', text);
|
|
527
|
-
}, [text]);
|
|
528
|
-
|
|
529
|
-
// Auto-save when user tries to close/reload the page
|
|
530
|
-
useBeforeUnload(text ? onSave : undefined);
|
|
531
|
-
```
|
|
532
|
-
> **Note:** Pass `undefined` to disable the handler (e.g., if there is no changes).
|
|
533
|
-
|
|
534
518
|
### `useQueryParam()`
|
|
535
519
|
|
|
536
520
|
A flexible hook for working with typed query parameters. You provide an adapter object with `parse` and `serialize` functions, and it returns the parsed value and a setter.
|
|
@@ -701,18 +685,6 @@ function ProductFilter() {
|
|
|
701
685
|
|
|
702
686
|
> **Note:** `getSearchParams` returns `string` for single values, `string[]` for multiple values, and `''` if the key is not found.
|
|
703
687
|
|
|
704
|
-
### `useHistoricalTrail()`
|
|
705
|
-
|
|
706
|
-
Returns an array of pathnames representing the user's actual navigation history. Perfect for **history-based breadcrumbs** in dashboards, admin panels, multi-step forms, or any app where users navigate non-linearly.
|
|
707
|
-
|
|
708
|
-
**Returns:** Array of pathnames in chronological visit order (e.g., `['/dashboard', '/users', '/settings']`)
|
|
709
|
-
|
|
710
|
-
**Key features:**
|
|
711
|
-
- **Chronological order** — Paths are stored in the order the user visited them
|
|
712
|
-
- **Unique entries** — Revisiting a page trims the trail to that point
|
|
713
|
-
- **Respects navigation blocking** — Only successful navigations are added
|
|
714
|
-
- **Redirect-safe** — Redirected pages are not added to the trail
|
|
715
|
-
|
|
716
688
|
## Lazy Loading
|
|
717
689
|
|
|
718
690
|
Clear Router supports code-splitting out of the box. Simply pass a function that returns a dynamic import:
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
type Options = Partial<{
|
|
2
|
+
onSuccess: (args: unknown) => void;
|
|
3
|
+
onError: (args: unknown) => void;
|
|
4
|
+
}> | undefined;
|
|
5
|
+
export declare const useAction: (action: string, options?: Options) => (formData: FormData) => Promise<void>;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const useActionParams: () => {
|
|
2
|
+
invalidate: (path?: string) => Promise<void>;
|
|
3
|
+
routeItem: import("..").RouteItem | undefined;
|
|
4
|
+
latestContext: import("react").RefObject<Record<string, unknown>>;
|
|
5
|
+
params: Record<string, string>;
|
|
6
|
+
setContext: (action: Record<string, unknown> | ((prevState: Record<string, unknown>) => Record<string, unknown>)) => void;
|
|
7
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -9,11 +9,9 @@ export { useLoaderState } from './hooks/useLoaderState';
|
|
|
9
9
|
export { useInvalidate } from './hooks/useInvalidate';
|
|
10
10
|
export { useBlocker } from './hooks/useBlocker';
|
|
11
11
|
export { useAction } from './hooks/useAction';
|
|
12
|
-
export { useBeforeUnload } from './hooks/useBeforeUnload';
|
|
13
12
|
export { useRouterContext } from './hooks/useRouterContext';
|
|
14
13
|
export { useQueryParam } from './hooks/useQueryParam';
|
|
15
14
|
export { useSearchParams } from './hooks/useSearchParams';
|
|
16
|
-
export { useHistoricalTrail } from './hooks/useHistoricalTrail';
|
|
17
15
|
export { useFormContext } from './hooks/useFormContext';
|
|
18
16
|
export { adapter } from './utils/adapter';
|
|
19
17
|
export { createRouter } from './utils/utils';
|
package/dist/index.js
CHANGED
|
@@ -112,7 +112,7 @@ var useCurrentLoaderState = createState(emptyLoaderState);
|
|
|
112
112
|
var useScrollMap = createState({});
|
|
113
113
|
var useContextState = createState({});
|
|
114
114
|
//#endregion
|
|
115
|
-
//#region \0@oxc-project+runtime@0.
|
|
115
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/typeof.js
|
|
116
116
|
function _typeof(o) {
|
|
117
117
|
"@babel/helpers - typeof";
|
|
118
118
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -122,7 +122,7 @@ function _typeof(o) {
|
|
|
122
122
|
}, _typeof(o);
|
|
123
123
|
}
|
|
124
124
|
//#endregion
|
|
125
|
-
//#region \0@oxc-project+runtime@0.
|
|
125
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPrimitive.js
|
|
126
126
|
function toPrimitive(t, r) {
|
|
127
127
|
if ("object" != _typeof(t) || !t) return t;
|
|
128
128
|
var e = t[Symbol.toPrimitive];
|
|
@@ -134,13 +134,13 @@ function toPrimitive(t, r) {
|
|
|
134
134
|
return ("string" === r ? String : Number)(t);
|
|
135
135
|
}
|
|
136
136
|
//#endregion
|
|
137
|
-
//#region \0@oxc-project+runtime@0.
|
|
137
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPropertyKey.js
|
|
138
138
|
function toPropertyKey(t) {
|
|
139
139
|
var i = toPrimitive(t, "string");
|
|
140
140
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
141
141
|
}
|
|
142
142
|
//#endregion
|
|
143
|
-
//#region \0@oxc-project+runtime@0.
|
|
143
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/defineProperty.js
|
|
144
144
|
function _defineProperty(e, r, t) {
|
|
145
145
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
146
146
|
value: t,
|
|
@@ -704,6 +704,15 @@ var Link = ({ children, to, prefetch: prefetchLink, hoverPrefetchDelay }) => {
|
|
|
704
704
|
});
|
|
705
705
|
};
|
|
706
706
|
//#endregion
|
|
707
|
+
//#region context/FormContext.ts
|
|
708
|
+
var FormContext = createContext({ isSubmitting: false });
|
|
709
|
+
//#endregion
|
|
710
|
+
//#region provider/FormProvider.tsx
|
|
711
|
+
var FormProvider = ({ children, isSubmitting }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormContext.Provider, {
|
|
712
|
+
value: { isSubmitting },
|
|
713
|
+
children
|
|
714
|
+
});
|
|
715
|
+
//#endregion
|
|
707
716
|
//#region hooks/useInvalidate.ts
|
|
708
717
|
var useInvalidate = () => {
|
|
709
718
|
const { invalidate } = useRouterActions();
|
|
@@ -714,41 +723,43 @@ var useInvalidate = () => {
|
|
|
714
723
|
var useParams = () => {
|
|
715
724
|
const [routeItemData] = useRouteItemData();
|
|
716
725
|
const { routeItem, location: { pathname } } = routeItemData;
|
|
717
|
-
|
|
718
|
-
return getParamsObject({
|
|
726
|
+
return useMemo(() => routeItem ? getParamsObject({
|
|
719
727
|
params: routeItem?.params,
|
|
720
728
|
pathname
|
|
721
|
-
});
|
|
729
|
+
}) : void 0, [pathname, routeItem]);
|
|
722
730
|
};
|
|
723
731
|
//#endregion
|
|
724
|
-
//#region
|
|
725
|
-
var
|
|
726
|
-
//#endregion
|
|
727
|
-
//#region provider/FormProvider.tsx
|
|
728
|
-
var FormProvider = ({ children, isSubmitting }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormContext.Provider, {
|
|
729
|
-
value: { isSubmitting },
|
|
730
|
-
children
|
|
731
|
-
});
|
|
732
|
-
//#endregion
|
|
733
|
-
//#region components/Form.tsx
|
|
734
|
-
var Form = ({ children, action: actionKey, onSuccess, onError, autoReset = true }) => {
|
|
732
|
+
//#region hooks/useActionParams.ts
|
|
733
|
+
var useActionParams = () => {
|
|
735
734
|
const invalidate = useInvalidate();
|
|
736
735
|
const [routeItemData] = useRouteItemData();
|
|
737
736
|
const [context, setContext] = useContextState();
|
|
738
737
|
const params = useParams();
|
|
739
738
|
const { routeItem } = routeItemData;
|
|
739
|
+
return {
|
|
740
|
+
invalidate,
|
|
741
|
+
routeItem,
|
|
742
|
+
latestContext: useLatest(context),
|
|
743
|
+
params,
|
|
744
|
+
setContext
|
|
745
|
+
};
|
|
746
|
+
};
|
|
747
|
+
//#endregion
|
|
748
|
+
//#region components/Form.tsx
|
|
749
|
+
var Form = ({ children, action: actionKey, onSuccess, onError, autoReset = true }) => {
|
|
750
|
+
const { invalidate, routeItem, latestContext, params, setContext } = useActionParams();
|
|
740
751
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
741
752
|
const onSubmit = async (evt) => {
|
|
742
753
|
evt.preventDefault();
|
|
743
|
-
if (!routeItem) throw new Error("
|
|
744
|
-
if (!routeItem.actions) throw new Error("
|
|
754
|
+
if (!routeItem) throw new Error("Route not found");
|
|
755
|
+
if (!routeItem.actions) throw new Error("Route action creator not found");
|
|
745
756
|
const action = routeItem.actions({
|
|
746
|
-
context,
|
|
757
|
+
context: latestContext.current,
|
|
747
758
|
setContext,
|
|
748
759
|
params,
|
|
749
760
|
invalidate
|
|
750
761
|
})[actionKey];
|
|
751
|
-
if (!action) throw new Error("
|
|
762
|
+
if (!action) throw new Error(`Action "${actionKey}" not found`);
|
|
752
763
|
try {
|
|
753
764
|
setIsSubmitting(true);
|
|
754
765
|
const result = await action(new FormData(evt.target));
|
|
@@ -821,53 +832,39 @@ var useBlocker = (blockerFn) => {
|
|
|
821
832
|
};
|
|
822
833
|
//#endregion
|
|
823
834
|
//#region hooks/useAction.ts
|
|
824
|
-
var useAction = (
|
|
825
|
-
const invalidate =
|
|
826
|
-
const
|
|
827
|
-
const
|
|
828
|
-
const params = useParams();
|
|
829
|
-
const { routeItem } = routeItemData;
|
|
830
|
-
const latestContext = useLatest(context);
|
|
835
|
+
var useAction = (action, options = {}) => {
|
|
836
|
+
const { invalidate, routeItem, latestContext, params, setContext } = useActionParams();
|
|
837
|
+
const latestOnSuccess = useLatest(options?.onSuccess);
|
|
838
|
+
const latestOnError = useLatest(options?.onError);
|
|
831
839
|
return useCallback(async (formData) => {
|
|
832
|
-
if (!routeItem) throw new Error("
|
|
833
|
-
if (!routeItem.actions) throw new Error("
|
|
834
|
-
const
|
|
840
|
+
if (!routeItem) throw new Error("Route not found");
|
|
841
|
+
if (!routeItem.actions) throw new Error("Route action creator not found");
|
|
842
|
+
const currentAction = routeItem.actions({
|
|
835
843
|
context: latestContext.current,
|
|
836
844
|
setContext,
|
|
837
845
|
params,
|
|
838
846
|
invalidate
|
|
839
|
-
})[
|
|
840
|
-
if (!
|
|
847
|
+
})[action];
|
|
848
|
+
if (!currentAction) throw new Error(`Action "${action}" not found`);
|
|
841
849
|
try {
|
|
842
|
-
await
|
|
850
|
+
const result = await currentAction(formData);
|
|
843
851
|
await invalidate();
|
|
852
|
+
latestOnSuccess.current?.(result);
|
|
844
853
|
} catch (error) {
|
|
845
|
-
|
|
854
|
+
latestOnError.current?.(error);
|
|
846
855
|
}
|
|
847
856
|
}, [
|
|
848
|
-
|
|
849
|
-
latestContext,
|
|
857
|
+
action,
|
|
850
858
|
invalidate,
|
|
851
|
-
|
|
859
|
+
latestContext,
|
|
860
|
+
latestOnError,
|
|
861
|
+
latestOnSuccess,
|
|
852
862
|
params,
|
|
853
863
|
routeItem,
|
|
854
864
|
setContext
|
|
855
865
|
]);
|
|
856
866
|
};
|
|
857
867
|
//#endregion
|
|
858
|
-
//#region hooks/useBeforeUnload.ts
|
|
859
|
-
var useBeforeUnload = (callback) => {
|
|
860
|
-
useEffect(() => {
|
|
861
|
-
const handler = (event) => {
|
|
862
|
-
if (!callback) return;
|
|
863
|
-
event.preventDefault();
|
|
864
|
-
callback();
|
|
865
|
-
};
|
|
866
|
-
window.addEventListener("beforeunload", handler);
|
|
867
|
-
return () => window.removeEventListener("beforeunload", handler);
|
|
868
|
-
}, [callback]);
|
|
869
|
-
};
|
|
870
|
-
//#endregion
|
|
871
868
|
//#region hooks/useRouterContext.ts
|
|
872
869
|
var useRouterContext = () => {
|
|
873
870
|
const [context, setContext] = useContextState();
|
|
@@ -962,20 +959,6 @@ function useQueryParam(field, adapter, defaultValue) {
|
|
|
962
959
|
])];
|
|
963
960
|
}
|
|
964
961
|
//#endregion
|
|
965
|
-
//#region hooks/useHistoricalTrail.ts
|
|
966
|
-
var useHistoricalTrail = () => {
|
|
967
|
-
const { pathname } = useLocation();
|
|
968
|
-
const [trail, setTrail] = useState([]);
|
|
969
|
-
useEffect(() => {
|
|
970
|
-
if (!pathname) return;
|
|
971
|
-
setTrail((prevState) => {
|
|
972
|
-
const index = prevState.indexOf(pathname);
|
|
973
|
-
return index === -1 ? [...prevState, pathname] : prevState.slice(0, index + 1);
|
|
974
|
-
});
|
|
975
|
-
}, [pathname]);
|
|
976
|
-
return trail;
|
|
977
|
-
};
|
|
978
|
-
//#endregion
|
|
979
962
|
//#region hooks/useFormContext.ts
|
|
980
963
|
var useFormContext = () => useContext(FormContext);
|
|
981
964
|
//#endregion
|
|
@@ -1041,4 +1024,4 @@ var adapter = {
|
|
|
1041
1024
|
})
|
|
1042
1025
|
};
|
|
1043
1026
|
//#endregion
|
|
1044
|
-
export { Form, Link, Router, RouterProvider, adapter, createRouter, useAction,
|
|
1027
|
+
export { Form, Link, Router, RouterProvider, adapter, createRouter, useAction, useBlocker, useFormContext, useInvalidate, useLoaderState, useLocation, useNavigate, useParams, useQueryParam, useRouterContext, useSearchParams };
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const useBeforeUnload: (callback?: () => void) => void;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const useHistoricalTrail: () => string[];
|