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 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, type Updater } from "../useCrud";
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
- description: string;
39
- complete: boolean;
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
- { id: "1", description: "Shop for electronics", complete: false },
56
- { id: "2", description: "Find time for learning", complete: false },
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: ItemWithState<Todo>;
67
- update: (item: ItemWithState<Todo>, updater: Updater<Todo>, isOptimistic?: boolean) => void;
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(item, (draft) => {
74
- draft.complete = !item.data.complete;
71
+ update((draft) => {
72
+ draft.completed = !data.completed;
75
73
  });
76
- }, [update, item]);
74
+ }, [update, data]);
77
75
 
78
76
  return (
79
- <div key={data.id} className="flex gap-2 mb-1">
80
- <div className={data.complete ? "line-through" : ""}>{data.description}</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
- className="bg-blue-300 px-2 rounded active:bg-blue-400 cursor-pointer font-bold"
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
- Complete
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 { items, isLoading, update } = useCrud(TodoCrud);
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 className="p-2">
100
- {map(items, (item) => (
101
- <Item key={item.data.id} item={item} update={update} />
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 CreateStoreConfig<T extends Item = Item> = {
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
- export declare class FetchCache {
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: unknown;
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
- action?: [TransitionStates, T];
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
- export declare type StoreOptions<T extends Item = Item> = {
71
- initialData?: T[];
72
- } & Pick<CrudConfig, "caching" | "debounce">;
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?: unknown;
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" | "error" | "changed";
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 Record<string, any> = any>(config: CrudConfig<T, C>): {
100
- itemsById: Map<string, ItemWithState<T>>;
101
- items: ItemWithState<T>[];
102
- metadata: unknown;
103
- isLoading: 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;
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: Omit<T, "id">) => void;
127
- update: (item: ItemWithState<T>, updater: Updater<T>, isOptimistic?: boolean) => void;
128
- change: (item: ItemWithState<T>, updater: Updater<T>) => void;
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 const useMemoDeepEquals: <T>(value: T) => T;
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 { }