use-abcd 0.1.1 → 0.2.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 +48 -29
- package/dist/useCrud.d.ts +89 -65
- package/dist/useCrud.js +1252 -1240
- package/package.json +1 -1
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";
|
|
34
|
+
import { useCrud, useItemState, type CrudConfig, type ItemWithState } from "../useCrud";
|
|
33
35
|
import { map } from "lodash-es";
|
|
34
|
-
import {
|
|
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,75 @@ 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: "three", description: "Pick stocks", complete: false },
|
|
58
|
-
],
|
|
54
|
+
items: await fetch("https://jsonplaceholder.typicode.com/todos")
|
|
55
|
+
.then((r) => r.json())
|
|
56
|
+
.then((items) => items.slice(0, 10)),
|
|
59
57
|
metadata: {},
|
|
60
58
|
};
|
|
61
59
|
},
|
|
60
|
+
update: async (item, { signal }) => {
|
|
61
|
+
await wait(1000, signal);
|
|
62
|
+
return { id: item.id };
|
|
63
|
+
},
|
|
62
64
|
};
|
|
63
65
|
|
|
64
|
-
const Item = React.memo((props: { item: ItemWithState<Todo> })
|
|
65
|
-
const item = props
|
|
66
|
-
const data = item
|
|
67
|
-
const { update } = useCrudOperations(TodoCrud);
|
|
66
|
+
const Item = React.memo(function Item(props: { item: ItemWithState<Todo> }) {
|
|
67
|
+
const { item } = props;
|
|
68
|
+
const [data, { update, states }] = useItemState("todo-crud", item);
|
|
68
69
|
|
|
69
70
|
const markComplete = useCallback(() => {
|
|
70
|
-
update(
|
|
71
|
-
draft.
|
|
71
|
+
update((draft) => {
|
|
72
|
+
draft.completed = !data.completed;
|
|
72
73
|
});
|
|
73
|
-
}, [update,
|
|
74
|
+
}, [update, data]);
|
|
74
75
|
|
|
75
76
|
return (
|
|
76
|
-
<div key={data.id} className="flex gap-2 mb-1">
|
|
77
|
-
<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>
|
|
78
85
|
<button
|
|
79
|
-
|
|
86
|
+
type="button"
|
|
87
|
+
className="bg-blue-300 px-2 rounded active:bg-blue-400 cursor-pointer font-bold disabled:opacity-40"
|
|
80
88
|
onClick={markComplete}
|
|
89
|
+
disabled={states.has("update")}
|
|
81
90
|
>
|
|
82
|
-
|
|
91
|
+
{states.has("update")
|
|
92
|
+
? "Updating..."
|
|
93
|
+
: data.completed
|
|
94
|
+
? "Mark incomplete"
|
|
95
|
+
: "Mark complete"}
|
|
83
96
|
</button>
|
|
84
97
|
</div>
|
|
85
98
|
);
|
|
86
99
|
});
|
|
87
100
|
|
|
88
|
-
export function Todo() {
|
|
89
|
-
const {
|
|
101
|
+
export const Todo = React.memo(function Todo() {
|
|
102
|
+
const {
|
|
103
|
+
items,
|
|
104
|
+
fetchState: { isLoading },
|
|
105
|
+
} = useCrud(TodoCrud);
|
|
90
106
|
|
|
91
107
|
if (isLoading) {
|
|
92
108
|
return <div>Loading...</div>;
|
|
93
109
|
}
|
|
94
110
|
|
|
95
111
|
return (
|
|
96
|
-
<div
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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>
|
|
100
119
|
</div>
|
|
101
120
|
);
|
|
102
|
-
}
|
|
121
|
+
});
|
|
103
122
|
```
|
|
104
123
|
|
|
105
124
|
> **Note**: This is a single-file library with a focused scope. Please read the source code for a deeper understanding of its implementation and capabilities.
|
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,50 +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:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
state: TransitionStates;
|
|
105
|
-
optimistic: boolean;
|
|
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;
|
|
106
137
|
errors: string[];
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
metadata: unknown;
|
|
110
|
-
isLoading: boolean;
|
|
138
|
+
metadata?: M;
|
|
139
|
+
};
|
|
111
140
|
hasError: boolean;
|
|
112
|
-
errors: string[];
|
|
113
|
-
create: (item: Omit<T, "id">) => void;
|
|
114
|
-
update: (item: ItemWithState<T>, updater: Updater<T>, isOptimistic?: boolean) => void;
|
|
115
|
-
change: (item: ItemWithState<T>, updater: Updater<T>) => void;
|
|
116
|
-
retry: (item: ItemWithState<T>) => void;
|
|
117
|
-
save: (item: ItemWithState<T>) => void;
|
|
118
|
-
remove: (item: ItemWithState<T>) => void;
|
|
119
141
|
cancelFetch: () => void;
|
|
120
|
-
cancelOperation: (id: string) => void;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Hook that provides CRUD operation handlers for managing items.
|
|
125
|
-
* @template T - Type of items to manage, must extend Item base type
|
|
126
|
-
* @template C - Type of context object used in operations
|
|
127
|
-
* @param config - Configuration object for CRUD operations
|
|
128
|
-
* @returns Object containing CRUD operation handlers and cancellation functions
|
|
129
|
-
*/
|
|
130
|
-
export declare function useCrudOperations<T extends Item = Item, C extends Record<string, any> = any>(config: CrudConfig<T, C>): {
|
|
131
|
-
fetch: () => void;
|
|
142
|
+
cancelOperation: (id: string, tag?: string) => void;
|
|
132
143
|
refetch: () => void;
|
|
133
|
-
create: (item:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
save: (item: ItemWithState<T>) => void;
|
|
137
|
-
retry: (item: ItemWithState<T>) => void;
|
|
138
|
-
remove: (item: ItemWithState<T>) => void;
|
|
139
|
-
cancelFetch: () => void;
|
|
140
|
-
cancelOperation: (id: string) => void;
|
|
144
|
+
create: (item: Partial<T>) => void;
|
|
145
|
+
remove: (item: T) => void;
|
|
146
|
+
store: Store<T, C, object>;
|
|
141
147
|
};
|
|
142
148
|
|
|
143
|
-
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
|
+
];
|
|
144
168
|
|
|
145
169
|
export { }
|