use-abcd 0.1.2 → 0.2.1
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 +46 -30
- package/dist/useCrud.d.ts +90 -59
- package/dist/useCrud.js +1190 -1164
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -29,14 +29,17 @@ bun add use-abcd
|
|
|
29
29
|
## Quick Example
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
|
+
// biome-ignore assist/source/organizeImports: useless
|
|
32
33
|
import React, { useCallback } from "react";
|
|
33
|
-
import { useCrud, type CrudConfig, type ItemWithState
|
|
34
|
+
import { useCrud, useItemState, type CrudConfig, type ItemWithState } from "../useCrud";
|
|
34
35
|
import { map } from "lodash-es";
|
|
36
|
+
import { wait } from "../utils";
|
|
35
37
|
|
|
36
38
|
type Todo = {
|
|
39
|
+
userId: string;
|
|
37
40
|
id: string;
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
title: string;
|
|
42
|
+
completed: boolean;
|
|
40
43
|
};
|
|
41
44
|
|
|
42
45
|
const TodoCrud: CrudConfig<Todo> = {
|
|
@@ -47,59 +50,72 @@ const TodoCrud: CrudConfig<Todo> = {
|
|
|
47
50
|
capacity: 10,
|
|
48
51
|
},
|
|
49
52
|
fetch: async () => {
|
|
50
|
-
await new Promise((resolve) => {
|
|
51
|
-
setTimeout(resolve, 200);
|
|
52
|
-
});
|
|
53
53
|
return {
|
|
54
|
-
items:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{ id: "3", description: "Pick stocks", complete: false },
|
|
58
|
-
{ id: "4", description: "Pick stocks", complete: false },
|
|
59
|
-
],
|
|
54
|
+
items: await fetch("https://jsonplaceholder.typicode.com/todos")
|
|
55
|
+
.then((r) => r.json())
|
|
56
|
+
.then((items) => items.slice(0, 10)),
|
|
60
57
|
metadata: {},
|
|
61
58
|
};
|
|
62
59
|
},
|
|
60
|
+
update: async (item, { signal }) => {
|
|
61
|
+
await wait(1000, signal);
|
|
62
|
+
return { id: item.id };
|
|
63
|
+
},
|
|
63
64
|
};
|
|
64
65
|
|
|
65
|
-
const Item = React.memo(function Item(props: {
|
|
66
|
-
item
|
|
67
|
-
|
|
68
|
-
}) {
|
|
69
|
-
const { update, item } = props;
|
|
70
|
-
const { data } = item;
|
|
66
|
+
const Item = React.memo(function Item(props: { item: ItemWithState<Todo> }) {
|
|
67
|
+
const { item } = props;
|
|
68
|
+
const [data, { update, states }] = useItemState("todo-crud", item);
|
|
71
69
|
|
|
72
70
|
const markComplete = useCallback(() => {
|
|
73
|
-
update(
|
|
74
|
-
draft.
|
|
71
|
+
update((draft) => {
|
|
72
|
+
draft.completed = !data.completed;
|
|
75
73
|
});
|
|
76
|
-
}, [update,
|
|
74
|
+
}, [update, data]);
|
|
77
75
|
|
|
78
76
|
return (
|
|
79
|
-
<div key={data.id} className="flex gap-2 mb-1">
|
|
80
|
-
<div
|
|
77
|
+
<div key={data.id} className="flex justify-between gap-2 mb-1 min-w-[500px]">
|
|
78
|
+
<div
|
|
79
|
+
className={
|
|
80
|
+
data.completed ? "line-through font-bold text-gray-700" : "font-bold text-gray-700"
|
|
81
|
+
}
|
|
82
|
+
>
|
|
83
|
+
{data.title}
|
|
84
|
+
</div>
|
|
81
85
|
<button
|
|
82
|
-
|
|
86
|
+
type="button"
|
|
87
|
+
className="bg-blue-300 px-2 rounded active:bg-blue-400 cursor-pointer font-bold disabled:opacity-40"
|
|
83
88
|
onClick={markComplete}
|
|
89
|
+
disabled={states.has("update")}
|
|
84
90
|
>
|
|
85
|
-
|
|
91
|
+
{states.has("update")
|
|
92
|
+
? "Updating..."
|
|
93
|
+
: data.completed
|
|
94
|
+
? "Mark incomplete"
|
|
95
|
+
: "Mark complete"}
|
|
86
96
|
</button>
|
|
87
97
|
</div>
|
|
88
98
|
);
|
|
89
99
|
});
|
|
90
100
|
|
|
91
101
|
export const Todo = React.memo(function Todo() {
|
|
92
|
-
const {
|
|
102
|
+
const {
|
|
103
|
+
items,
|
|
104
|
+
fetchState: { isLoading },
|
|
105
|
+
} = useCrud(TodoCrud);
|
|
93
106
|
|
|
94
107
|
if (isLoading) {
|
|
95
108
|
return <div>Loading...</div>;
|
|
96
109
|
}
|
|
97
110
|
|
|
98
111
|
return (
|
|
99
|
-
<div
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
112
|
+
<div>
|
|
113
|
+
<h2 className="font-bold text-3xl mt-4">Todo with useCrud()</h2>
|
|
114
|
+
<div className="p-2">
|
|
115
|
+
{map(items, (item) => (
|
|
116
|
+
<Item key={item.data.id} item={item} />
|
|
117
|
+
))}
|
|
118
|
+
</div>
|
|
103
119
|
</div>
|
|
104
120
|
);
|
|
105
121
|
});
|
package/dist/useCrud.d.ts
CHANGED
|
@@ -3,17 +3,7 @@ declare type CachedItem = {
|
|
|
3
3
|
ts: number;
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
-
export declare type
|
|
7
|
-
id: string;
|
|
8
|
-
initialData?: T[];
|
|
9
|
-
debounce?: number;
|
|
10
|
-
caching?: {
|
|
11
|
-
capacity: number;
|
|
12
|
-
age: number;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export declare type CrudConfig<T extends Item = Item, C = any> = {
|
|
6
|
+
export declare type CrudConfig<T extends Item = Item, C extends object = object, M extends object = object> = {
|
|
17
7
|
id: string;
|
|
18
8
|
context: C;
|
|
19
9
|
debounce?: number;
|
|
@@ -21,7 +11,7 @@ export declare type CrudConfig<T extends Item = Item, C = any> = {
|
|
|
21
11
|
capacity: number;
|
|
22
12
|
age: number;
|
|
23
13
|
};
|
|
24
|
-
fetch?: FetchFn<T>;
|
|
14
|
+
fetch?: FetchFn<T, M>;
|
|
25
15
|
create?: TransitionFn<T>;
|
|
26
16
|
update?: TransitionFn<T>;
|
|
27
17
|
remove?: TransitionFn<T>;
|
|
@@ -32,7 +22,7 @@ export declare type CrudConfig<T extends Item = Item, C = any> = {
|
|
|
32
22
|
* Cache implementation for storing and managing fetch results
|
|
33
23
|
* with configurable age and capacity limits.
|
|
34
24
|
*/
|
|
35
|
-
|
|
25
|
+
declare class FetchCache {
|
|
36
26
|
age: number;
|
|
37
27
|
capacity: number;
|
|
38
28
|
storage: Map<string, CachedItem>;
|
|
@@ -45,21 +35,20 @@ export declare class FetchCache {
|
|
|
45
35
|
withCache: (id: string, callback: () => Promise<unknown>) => Promise<unknown>;
|
|
46
36
|
}
|
|
47
37
|
|
|
48
|
-
export declare type FetchFn<T extends Item = Item> = (option: QueryOption) => Promise<{
|
|
38
|
+
export declare type FetchFn<T extends Item = Item, M extends object = object> = (option: QueryOption) => Promise<{
|
|
49
39
|
items: T[];
|
|
50
|
-
metadata
|
|
40
|
+
metadata?: M;
|
|
51
41
|
}>;
|
|
52
42
|
|
|
53
43
|
export declare type Item = {
|
|
54
44
|
id: string;
|
|
55
45
|
} & Record<string, any>;
|
|
56
46
|
|
|
57
|
-
export declare type ItemWithState<T extends Item = Item> = {
|
|
47
|
+
export declare type ItemWithState<T extends Item = Item, State extends TransitionStates = TransitionStates> = {
|
|
58
48
|
data: T;
|
|
59
|
-
state: TransitionStates;
|
|
60
49
|
optimistic: boolean;
|
|
61
|
-
errors: string[]
|
|
62
|
-
|
|
50
|
+
errors: Map<string, string[]>;
|
|
51
|
+
transitions: Map<string | "default", [State, State extends "idle" ? undefined : T, ts: number]>;
|
|
63
52
|
};
|
|
64
53
|
|
|
65
54
|
export declare type QueryOption = {
|
|
@@ -67,24 +56,68 @@ export declare type QueryOption = {
|
|
|
67
56
|
context: unknown;
|
|
68
57
|
};
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Core state management store for CRUD operations.
|
|
61
|
+
* Handles data fetching, caching, and state transitions for items.
|
|
62
|
+
* @template T - Type of items managed by the store, must extend Item base type
|
|
63
|
+
*/
|
|
64
|
+
declare class Store<T extends Item = Item, C extends object = object, M extends object = object> {
|
|
65
|
+
private id;
|
|
66
|
+
private config;
|
|
67
|
+
batched: boolean;
|
|
68
|
+
state: StoreState<T, C, M>;
|
|
69
|
+
subscribers: Set<() => void>;
|
|
70
|
+
controllers: Map<string, AbortController>;
|
|
71
|
+
fetchController: AbortController;
|
|
72
|
+
fetchCache: FetchCache;
|
|
73
|
+
constructor(id: string, config: CrudConfig<T, C, M>);
|
|
74
|
+
executeFetch: (newContext: C) => Promise<void>;
|
|
75
|
+
executeRemove: (input: T) => Promise<void>;
|
|
76
|
+
executeUpdate: ({ item, updater, isOptimistic, skipSave, tag, }: {
|
|
77
|
+
item: T;
|
|
78
|
+
updater?: Updater<T>;
|
|
79
|
+
isOptimistic?: boolean;
|
|
80
|
+
skipSave?: boolean;
|
|
81
|
+
tag?: string;
|
|
82
|
+
}) => Promise<void>;
|
|
83
|
+
executeCreate: (input: Partial<T>) => Promise<void>;
|
|
84
|
+
private getCacheKey;
|
|
85
|
+
private getControlerId;
|
|
86
|
+
customLog: (title?: string, ...messages: any[]) => void;
|
|
87
|
+
private batch;
|
|
88
|
+
private setItems;
|
|
89
|
+
private setMetadata;
|
|
90
|
+
private setContext;
|
|
91
|
+
private remove;
|
|
92
|
+
private updateItem;
|
|
93
|
+
clearFetchCache: () => void;
|
|
94
|
+
private startFetch;
|
|
95
|
+
private endFetch;
|
|
96
|
+
cancelFetch: () => void;
|
|
97
|
+
cancelOperation: (id: string, tag?: string) => void;
|
|
98
|
+
private startTransition;
|
|
99
|
+
private notify;
|
|
100
|
+
getSnapshot: () => StoreState<T, C, M>;
|
|
101
|
+
subscribe: (fn: () => void) => () => void;
|
|
102
|
+
static instances: Map<string, Store<any>>;
|
|
103
|
+
static createStore<T extends Item = Item, C extends object = object, M extends object = object>(config: CrudConfig<T, C, M>): Store<T, C>;
|
|
104
|
+
}
|
|
73
105
|
|
|
74
|
-
export declare type StoreState<T extends Item = Item> = {
|
|
106
|
+
export declare type StoreState<T extends Item = Item, C extends object = object, M extends object = object> = {
|
|
107
|
+
context: C;
|
|
108
|
+
items: Map<string, ItemWithState<T>>;
|
|
75
109
|
fetchState: {
|
|
76
110
|
isLoading: boolean;
|
|
77
111
|
errors: string[];
|
|
78
|
-
metadata?:
|
|
112
|
+
metadata?: M;
|
|
79
113
|
};
|
|
80
|
-
items: Map<string, ItemWithState<T>>;
|
|
81
114
|
};
|
|
82
115
|
|
|
83
116
|
export declare type TransitionFn<T extends Item = Item> = (item: Partial<T>, option: QueryOption) => Promise<{
|
|
84
117
|
id: string;
|
|
85
118
|
}>;
|
|
86
119
|
|
|
87
|
-
export declare type TransitionStates = "create" | "update" | "delete" | "idle" | "
|
|
120
|
+
export declare type TransitionStates = "create" | "update" | "delete" | "idle" | "changed";
|
|
88
121
|
|
|
89
122
|
export declare type Updater<T> = (updatable: T) => void;
|
|
90
123
|
|
|
@@ -96,43 +129,41 @@ export declare type Updater<T> = (updatable: T) => void;
|
|
|
96
129
|
* @param config - Configuration object for CRUD operations
|
|
97
130
|
* @returns Object containing items, state information, and CRUD operation handlers
|
|
98
131
|
*/
|
|
99
|
-
export declare function useCrud<T extends Item = Item, C extends
|
|
100
|
-
itemsById: Map<string, ItemWithState<T>>;
|
|
101
|
-
items: ItemWithState<T>[];
|
|
102
|
-
|
|
103
|
-
|
|
132
|
+
export declare function useCrud<T extends Item = Item, C extends object = object, M extends object = object>(config: CrudConfig<T, C, M>): {
|
|
133
|
+
itemsById: Map<string, ItemWithState<T, TransitionStates>>;
|
|
134
|
+
items: ItemWithState<T, TransitionStates>[];
|
|
135
|
+
fetchState: {
|
|
136
|
+
isLoading: boolean;
|
|
137
|
+
errors: string[];
|
|
138
|
+
metadata?: M;
|
|
139
|
+
};
|
|
104
140
|
hasError: boolean;
|
|
105
|
-
errors: string[];
|
|
106
|
-
create: (item: Omit<T, "id">) => void;
|
|
107
|
-
update: (item: ItemWithState<T>, updater: Updater<T>, isOptimistic?: boolean) => void;
|
|
108
|
-
change: (item: ItemWithState<T>, updater: Updater<T>) => void;
|
|
109
|
-
retry: (item: ItemWithState<T>) => void;
|
|
110
|
-
save: (item: ItemWithState<T>) => void;
|
|
111
|
-
remove: (item: ItemWithState<T>) => void;
|
|
112
141
|
cancelFetch: () => void;
|
|
113
|
-
cancelOperation: (id: string) => void;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Hook that provides CRUD operation handlers for managing items.
|
|
118
|
-
* @template T - Type of items to manage, must extend Item base type
|
|
119
|
-
* @template C - Type of context object used in operations
|
|
120
|
-
* @param config - Configuration object for CRUD operations
|
|
121
|
-
* @returns Object containing CRUD operation handlers and cancellation functions
|
|
122
|
-
*/
|
|
123
|
-
export declare function useCrudOperations<T extends Item = Item, C extends Record<string, any> = any>(config: CrudConfig<T, C>): {
|
|
124
|
-
fetch: () => void;
|
|
142
|
+
cancelOperation: (id: string, tag?: string) => void;
|
|
125
143
|
refetch: () => void;
|
|
126
|
-
create: (item:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
save: (item: ItemWithState<T>) => void;
|
|
130
|
-
retry: (item: ItemWithState<T>) => void;
|
|
131
|
-
remove: (item: ItemWithState<T>) => void;
|
|
132
|
-
cancelFetch: () => void;
|
|
133
|
-
cancelOperation: (id: string) => void;
|
|
144
|
+
create: (item: Partial<T>) => void;
|
|
145
|
+
remove: (item: T) => void;
|
|
146
|
+
store: Store<T, C, object>;
|
|
134
147
|
};
|
|
135
148
|
|
|
136
|
-
export declare
|
|
149
|
+
export declare function useItemState<T extends Item = Item>(storeId: string, item: ItemWithState<T>): [
|
|
150
|
+
T,
|
|
151
|
+
{
|
|
152
|
+
errors: Map<string, string[]>;
|
|
153
|
+
states: Set<string>;
|
|
154
|
+
save: () => void;
|
|
155
|
+
change: (cb: Updater<T>, tag?: string) => void;
|
|
156
|
+
update: (cb: Updater<T>, options?: {
|
|
157
|
+
tag?: string;
|
|
158
|
+
isOptimistic?: boolean;
|
|
159
|
+
}) => void;
|
|
160
|
+
remove: () => void;
|
|
161
|
+
cancel: () => void;
|
|
162
|
+
hasError: boolean;
|
|
163
|
+
errorCount: number;
|
|
164
|
+
itemWithState: ItemWithState<T>;
|
|
165
|
+
store: Store<T>;
|
|
166
|
+
}
|
|
167
|
+
];
|
|
137
168
|
|
|
138
169
|
export { }
|