@daviapps/react-utils 0.0.3 → 0.0.5

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/form/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AxiosError } from "axios";
2
- // import type { FieldValues, UseFormReturn } from "react-hook-form";
2
+
3
3
  import z, {
4
4
  ZodArray,
5
5
  ZodBoolean,
@@ -12,9 +12,11 @@ import z, {
12
12
  ZodString,
13
13
  } from "zod/v3";
14
14
 
15
+ import { type UseFormReturn } from "react-hook-form";
16
+
15
17
  export function zodSchemaDefaults<S extends ZodObject<any>, T = z.infer<S>>(
16
18
  schema: S,
17
- overrides?: T
19
+ overrides?: T,
18
20
  ): any {
19
21
  return (Object.entries(schema._def.shape()) as [keyof T, ZodSchema][]).reduce(
20
22
  (acc, [key, value]) => {
@@ -23,7 +25,7 @@ export function zodSchemaDefaults<S extends ZodObject<any>, T = z.infer<S>>(
23
25
  if (value instanceof ZodObject) {
24
26
  acc[key] = zodSchemaDefaults(
25
27
  value,
26
- defaultValue
28
+ defaultValue,
27
29
  ) as unknown as T[keyof T];
28
30
  } else if (
29
31
  value instanceof ZodArray ||
@@ -55,7 +57,7 @@ export function zodSchemaDefaults<S extends ZodObject<any>, T = z.infer<S>>(
55
57
  }
56
58
  return acc;
57
59
  },
58
- {} as T
60
+ {} as T,
59
61
  );
60
62
  }
61
63
 
@@ -64,10 +66,9 @@ export interface ServerValidationErrorResponse {
64
66
  fieldErrors: Map<string, Array<string>>;
65
67
  }
66
68
 
67
- export function zodServerResolver(
68
- e: AxiosError,
69
- form: any /*UseFormReturn<any>*/
70
- ) {
69
+ export function zodServerResolver(e: Error, form: UseFormReturn<any>) {
70
+ if (!(e instanceof AxiosError)) return;
71
+
71
72
  const data = e.response?.data as ServerValidationErrorResponse | undefined;
72
73
  if (!data) return;
73
74
 
package/hooks/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./use-local-state";
2
+ export * from "./use-session-state";
@@ -0,0 +1,80 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ useEffect,
5
+ useState,
6
+ type Dispatch,
7
+ type PropsWithChildren,
8
+ type SetStateAction,
9
+ } from "react";
10
+
11
+ export interface UseLocalStateProps<T> {
12
+ key: string;
13
+ initialState?: T | (() => T);
14
+ enabled?: boolean;
15
+ }
16
+
17
+ export function useLocalState<T>({
18
+ key,
19
+ initialState,
20
+ enabled = true,
21
+ }: UseLocalStateProps<T>) {
22
+ const context = useContext(LocalStateContext);
23
+ if (!context) throw new Error("LocalStateProvider required");
24
+
25
+ const state = useState<T>(context.data[key] ?? (initialState as T));
26
+ const [value] = state;
27
+
28
+ // Initial value
29
+ useEffect(() => {
30
+ if (!enabled) return;
31
+ const value = context.data[key];
32
+ if (!value) return;
33
+ state[1](value);
34
+ }, [enabled]);
35
+
36
+ // Dispatch changes to context
37
+ useEffect(() => {
38
+ if (!enabled) return;
39
+ context.setData((prev) => ({ ...prev, [key]: value }));
40
+ }, [value, enabled]);
41
+
42
+ return state;
43
+ }
44
+
45
+ export type LocalStateContextProps<S> = {
46
+ data: S;
47
+ setData: Dispatch<SetStateAction<S>>;
48
+ };
49
+
50
+ export const LocalStateContext = createContext<
51
+ LocalStateContextProps<{ [key: string]: any }> | undefined
52
+ >(undefined);
53
+
54
+ export interface LocalStateProviderProps extends PropsWithChildren {
55
+ storageKey?: string;
56
+ }
57
+
58
+ export function LocalStateProvider({
59
+ children,
60
+ storageKey = "local-state",
61
+ }: LocalStateProviderProps) {
62
+ const [data, setData] = useState(
63
+ JSON.parse(localStorage.getItem(storageKey) || "null") || {},
64
+ );
65
+
66
+ useEffect(() => {
67
+ localStorage.setItem(storageKey, JSON.stringify(data));
68
+ }, [data]);
69
+
70
+ return (
71
+ <LocalStateContext.Provider
72
+ value={{
73
+ data,
74
+ setData,
75
+ }}
76
+ >
77
+ {children}
78
+ </LocalStateContext.Provider>
79
+ );
80
+ }
@@ -0,0 +1,72 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ useEffect,
5
+ useState,
6
+ type Dispatch,
7
+ type PropsWithChildren,
8
+ type SetStateAction,
9
+ } from "react";
10
+
11
+ export interface UseSessionStateProps<T> {
12
+ key: string;
13
+ initialState?: T | (() => T);
14
+ enabled?: boolean;
15
+ }
16
+
17
+ export function useSessionState<T>({
18
+ key,
19
+ initialState,
20
+ enabled = true,
21
+ }: UseSessionStateProps<T>) {
22
+ const context = useContext(SessionStateContext);
23
+ if (!context) throw new Error("SessionStateProvider required");
24
+
25
+ const state = useState<T>(context.data[key] ?? (initialState as T));
26
+ const [value] = state;
27
+
28
+ // Dispatch changes to context
29
+ useEffect(() => {
30
+ if (!enabled) return;
31
+ context.setData((prev) => ({ ...prev, [key]: value }));
32
+ }, [value, enabled]);
33
+
34
+ return state;
35
+ }
36
+
37
+ export type SessionStateContextProps<S> = {
38
+ data: S;
39
+ setData: Dispatch<SetStateAction<S>>;
40
+ };
41
+
42
+ export const SessionStateContext = createContext<
43
+ SessionStateContextProps<{ [key: string]: any }> | undefined
44
+ >(undefined);
45
+
46
+ export interface SessionStateProviderProps extends PropsWithChildren {
47
+ storageKey?: string;
48
+ }
49
+
50
+ export function SessionStateProvider({
51
+ children,
52
+ storageKey = "session-state",
53
+ }: SessionStateProviderProps) {
54
+ const [data, setData] = useState(
55
+ JSON.parse(sessionStorage.getItem(storageKey) || "null") || {},
56
+ );
57
+
58
+ useEffect(() => {
59
+ sessionStorage.setItem(storageKey, JSON.stringify(data));
60
+ }, [data]);
61
+
62
+ return (
63
+ <SessionStateContext.Provider
64
+ value={{
65
+ data,
66
+ setData,
67
+ }}
68
+ >
69
+ {children}
70
+ </SessionStateContext.Provider>
71
+ );
72
+ }
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "@daviapps/react-utils",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "dependencies": {
6
+ "@trpc/client": "^11.7.1",
6
7
  "axios": "^1.13.2",
8
+ "react": "^19.2.4",
7
9
  "react-hook-form": "7.51.5",
8
10
  "zod": "^4.1.12"
11
+ },
12
+ "devDependencies": {
13
+ "@types/react": "^19.2.13"
9
14
  }
10
15
  }
@@ -0,0 +1,33 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "types": ["vite/client"],
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": false,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true,
26
+
27
+ "baseUrl": ".",
28
+ "paths": {
29
+ "@/*": ["./src/*"]
30
+ }
31
+ },
32
+ "include": ["src", "_dep/layouts", "_dep/views"]
33
+ }
package/tsconfig.json CHANGED
@@ -1,27 +1,13 @@
1
1
  {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ],
2
7
  "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
4
- "target": "ES2023",
5
- "lib": ["ES2023"],
6
- "module": "ESNext",
7
- // "types": ["node"],
8
- "skipLibCheck": true,
9
-
10
- /* Bundler mode */
11
- "moduleResolution": "bundler",
12
- "allowImportingTsExtensions": true,
13
- "verbatimModuleSyntax": true,
14
- "moduleDetection": "force",
15
- "noEmit": true,
16
-
17
- /* Linting */
18
- "strict": true,
19
- "noUnusedLocals": true,
20
- "noUnusedParameters": true,
21
- "erasableSyntaxOnly": false,
22
- "noFallthroughCasesInSwitch": true,
23
- "noUncheckedSideEffectImports": true,
24
-
25
- "baseUrl": "."
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": ["./src/*"]
11
+ }
26
12
  }
27
13
  }
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": false,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true,
24
+
25
+ "baseUrl": ".",
26
+ "paths": {
27
+ "@/*": ["./src/*"]
28
+ }
29
+ },
30
+ "include": ["vite.config.ts"]
31
+ }