@void-snippets/react 0.1.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/dist/index.d.mts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +152 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +130 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +44 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
|
+
import { ResourceService } from '@void-snippets/client';
|
|
3
|
+
import { ResourceAdapters, TQueryParams, TPagination, TDefaultPaginatedResponse, TDefaultSingleResponse, ResourceListResult } from '@void-snippets/core';
|
|
4
|
+
|
|
5
|
+
type Capitalize<S extends string> = S extends `${infer F}${infer Rest}` ? `${Uppercase<F>}${Rest}` : S;
|
|
6
|
+
type UseListReturn<K extends string, TBase> = {
|
|
7
|
+
[P in K]: TBase[];
|
|
8
|
+
} & {
|
|
9
|
+
pagination: TPagination;
|
|
10
|
+
} & {
|
|
11
|
+
[P in `is${Capitalize<K>}Loading`]: boolean;
|
|
12
|
+
} & {
|
|
13
|
+
[P in `${K}Error`]: Error | null;
|
|
14
|
+
} & {
|
|
15
|
+
[P in `invalidate${Capitalize<K>}`]: () => void;
|
|
16
|
+
};
|
|
17
|
+
interface CreateResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail> {
|
|
18
|
+
/**
|
|
19
|
+
* Adapters let you map your API's raw response shapes to the library's
|
|
20
|
+
* internal format. If your API matches the default shape
|
|
21
|
+
* ({ data: { items, page, limit, totalPages, totalDocuments } })
|
|
22
|
+
* you can omit this entirely.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* createResourceHooks("contacts", ContactsApis, {
|
|
26
|
+
* adapters: {
|
|
27
|
+
* fromList: (raw) => ({
|
|
28
|
+
* items: raw.results,
|
|
29
|
+
* pagination: { page: raw.page, limit: raw.perPage, totalPages: raw.pages, totalDocuments: raw.total },
|
|
30
|
+
* }),
|
|
31
|
+
* fromSingle: (raw) => raw.payload,
|
|
32
|
+
* }
|
|
33
|
+
* })
|
|
34
|
+
*/
|
|
35
|
+
adapters?: ResourceAdapters<TListRaw, TBase, TSingleRaw, TDetail>;
|
|
36
|
+
/**
|
|
37
|
+
* Default params for useList and useInfinite.
|
|
38
|
+
* @default { page: 1, limit: 10 }
|
|
39
|
+
*/
|
|
40
|
+
defaultParams?: TQueryParams;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a set of TanStack Query hooks for a resource.
|
|
44
|
+
*
|
|
45
|
+
* @param queryKeyPrefix - Used as the TanStack Query cache key prefix AND
|
|
46
|
+
* to name the returned hook properties dynamically.
|
|
47
|
+
* e.g. "contacts" → { contacts, isContactsLoading, ... }
|
|
48
|
+
* @param apiService - An instance of ResourceService (or a subclass).
|
|
49
|
+
* @param options - Optional adapters and default params.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // contacts.hooks.ts
|
|
53
|
+
* import { createResourceHooks } from '@void-snippets/react';
|
|
54
|
+
* import { ContactsApis } from './contacts.api';
|
|
55
|
+
*
|
|
56
|
+
* export const contactHooks = createResourceHooks('contacts', ContactsApis);
|
|
57
|
+
*
|
|
58
|
+
* // In a component:
|
|
59
|
+
* const { contacts, isContactsLoading } = contactHooks.useList();
|
|
60
|
+
* const { data } = contactHooks.useGet(id);
|
|
61
|
+
* const { create, update, delete: deleteContact } = contactHooks.useMutations();
|
|
62
|
+
*/
|
|
63
|
+
declare function createResourceHooks<K extends string, TId, TBase, TDetail = TBase, TCreate = Partial<TBase>, TUpdate = Partial<TBase>, TListRaw = TDefaultPaginatedResponse<TBase>, TSingleRaw = TDefaultSingleResponse<TDetail>>(queryKeyPrefix: K, apiService: ResourceService<TId, TBase, TDetail, TCreate, TUpdate, TListRaw, TSingleRaw>, options?: CreateResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail>): {
|
|
64
|
+
useList: (params?: TQueryParams) => UseListReturn<K, TBase>;
|
|
65
|
+
useGet: (id: TId, staleTime?: number) => {
|
|
66
|
+
data: _tanstack_react_query.NoInfer<TDetail> | undefined;
|
|
67
|
+
isLoading: boolean;
|
|
68
|
+
error: Error | null;
|
|
69
|
+
refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<_tanstack_react_query.NoInfer<TDetail>, Error>>;
|
|
70
|
+
};
|
|
71
|
+
useMutations: () => {
|
|
72
|
+
create: _tanstack_react_query.UseMutationResult<TDetail, Error, TCreate, unknown>;
|
|
73
|
+
update: _tanstack_react_query.UseMutationResult<TDetail, Error, {
|
|
74
|
+
_id: TId;
|
|
75
|
+
payload: TUpdate;
|
|
76
|
+
}, unknown>;
|
|
77
|
+
delete: _tanstack_react_query.UseMutationResult<TDetail, Error, TId, unknown>;
|
|
78
|
+
};
|
|
79
|
+
useInfinite: (params?: TQueryParams) => _tanstack_react_query.UseInfiniteQueryResult<_tanstack_react_query.InfiniteData<ResourceListResult<TBase>, unknown>, Error>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export { type CreateResourceHooksOptions, type UseListReturn, createResourceHooks };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
|
+
import { ResourceService } from '@void-snippets/client';
|
|
3
|
+
import { ResourceAdapters, TQueryParams, TPagination, TDefaultPaginatedResponse, TDefaultSingleResponse, ResourceListResult } from '@void-snippets/core';
|
|
4
|
+
|
|
5
|
+
type Capitalize<S extends string> = S extends `${infer F}${infer Rest}` ? `${Uppercase<F>}${Rest}` : S;
|
|
6
|
+
type UseListReturn<K extends string, TBase> = {
|
|
7
|
+
[P in K]: TBase[];
|
|
8
|
+
} & {
|
|
9
|
+
pagination: TPagination;
|
|
10
|
+
} & {
|
|
11
|
+
[P in `is${Capitalize<K>}Loading`]: boolean;
|
|
12
|
+
} & {
|
|
13
|
+
[P in `${K}Error`]: Error | null;
|
|
14
|
+
} & {
|
|
15
|
+
[P in `invalidate${Capitalize<K>}`]: () => void;
|
|
16
|
+
};
|
|
17
|
+
interface CreateResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail> {
|
|
18
|
+
/**
|
|
19
|
+
* Adapters let you map your API's raw response shapes to the library's
|
|
20
|
+
* internal format. If your API matches the default shape
|
|
21
|
+
* ({ data: { items, page, limit, totalPages, totalDocuments } })
|
|
22
|
+
* you can omit this entirely.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* createResourceHooks("contacts", ContactsApis, {
|
|
26
|
+
* adapters: {
|
|
27
|
+
* fromList: (raw) => ({
|
|
28
|
+
* items: raw.results,
|
|
29
|
+
* pagination: { page: raw.page, limit: raw.perPage, totalPages: raw.pages, totalDocuments: raw.total },
|
|
30
|
+
* }),
|
|
31
|
+
* fromSingle: (raw) => raw.payload,
|
|
32
|
+
* }
|
|
33
|
+
* })
|
|
34
|
+
*/
|
|
35
|
+
adapters?: ResourceAdapters<TListRaw, TBase, TSingleRaw, TDetail>;
|
|
36
|
+
/**
|
|
37
|
+
* Default params for useList and useInfinite.
|
|
38
|
+
* @default { page: 1, limit: 10 }
|
|
39
|
+
*/
|
|
40
|
+
defaultParams?: TQueryParams;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a set of TanStack Query hooks for a resource.
|
|
44
|
+
*
|
|
45
|
+
* @param queryKeyPrefix - Used as the TanStack Query cache key prefix AND
|
|
46
|
+
* to name the returned hook properties dynamically.
|
|
47
|
+
* e.g. "contacts" → { contacts, isContactsLoading, ... }
|
|
48
|
+
* @param apiService - An instance of ResourceService (or a subclass).
|
|
49
|
+
* @param options - Optional adapters and default params.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // contacts.hooks.ts
|
|
53
|
+
* import { createResourceHooks } from '@void-snippets/react';
|
|
54
|
+
* import { ContactsApis } from './contacts.api';
|
|
55
|
+
*
|
|
56
|
+
* export const contactHooks = createResourceHooks('contacts', ContactsApis);
|
|
57
|
+
*
|
|
58
|
+
* // In a component:
|
|
59
|
+
* const { contacts, isContactsLoading } = contactHooks.useList();
|
|
60
|
+
* const { data } = contactHooks.useGet(id);
|
|
61
|
+
* const { create, update, delete: deleteContact } = contactHooks.useMutations();
|
|
62
|
+
*/
|
|
63
|
+
declare function createResourceHooks<K extends string, TId, TBase, TDetail = TBase, TCreate = Partial<TBase>, TUpdate = Partial<TBase>, TListRaw = TDefaultPaginatedResponse<TBase>, TSingleRaw = TDefaultSingleResponse<TDetail>>(queryKeyPrefix: K, apiService: ResourceService<TId, TBase, TDetail, TCreate, TUpdate, TListRaw, TSingleRaw>, options?: CreateResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail>): {
|
|
64
|
+
useList: (params?: TQueryParams) => UseListReturn<K, TBase>;
|
|
65
|
+
useGet: (id: TId, staleTime?: number) => {
|
|
66
|
+
data: _tanstack_react_query.NoInfer<TDetail> | undefined;
|
|
67
|
+
isLoading: boolean;
|
|
68
|
+
error: Error | null;
|
|
69
|
+
refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<_tanstack_react_query.NoInfer<TDetail>, Error>>;
|
|
70
|
+
};
|
|
71
|
+
useMutations: () => {
|
|
72
|
+
create: _tanstack_react_query.UseMutationResult<TDetail, Error, TCreate, unknown>;
|
|
73
|
+
update: _tanstack_react_query.UseMutationResult<TDetail, Error, {
|
|
74
|
+
_id: TId;
|
|
75
|
+
payload: TUpdate;
|
|
76
|
+
}, unknown>;
|
|
77
|
+
delete: _tanstack_react_query.UseMutationResult<TDetail, Error, TId, unknown>;
|
|
78
|
+
};
|
|
79
|
+
useInfinite: (params?: TQueryParams) => _tanstack_react_query.UseInfiniteQueryResult<_tanstack_react_query.InfiniteData<ResourceListResult<TBase>, unknown>, Error>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export { type CreateResourceHooksOptions, type UseListReturn, createResourceHooks };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createResourceHooks: () => createResourceHooks
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/hooks/createResourceHooks.ts
|
|
28
|
+
var import_react_query = require("@tanstack/react-query");
|
|
29
|
+
var import_core = require("@void-snippets/core");
|
|
30
|
+
var DEFAULT_PAGINATION = {
|
|
31
|
+
page: 1,
|
|
32
|
+
limit: 10
|
|
33
|
+
};
|
|
34
|
+
function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
35
|
+
const {
|
|
36
|
+
adapters = (0, import_core.createDefaultAdapters)(),
|
|
37
|
+
defaultParams = DEFAULT_PAGINATION
|
|
38
|
+
} = options;
|
|
39
|
+
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
40
|
+
const capPrefix = capitalize(queryKeyPrefix);
|
|
41
|
+
return {
|
|
42
|
+
// -------------------------------------------------------------------------
|
|
43
|
+
// useList — paginated list with invalidation helper
|
|
44
|
+
// -------------------------------------------------------------------------
|
|
45
|
+
useList: (params = defaultParams) => {
|
|
46
|
+
var _a, _b, _c, _d, _e;
|
|
47
|
+
const queryClient = (0, import_react_query.useQueryClient)();
|
|
48
|
+
const queryKey = [queryKeyPrefix, params];
|
|
49
|
+
const query = (0, import_react_query.useQuery)({
|
|
50
|
+
queryKey,
|
|
51
|
+
queryFn: async () => {
|
|
52
|
+
const raw = await apiService.list(params);
|
|
53
|
+
return adapters.fromList(raw);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
const items = (_b = (_a = query.data) == null ? void 0 : _a.items) != null ? _b : [];
|
|
57
|
+
const pagination = (_e = (_c = query.data) == null ? void 0 : _c.pagination) != null ? _e : {
|
|
58
|
+
page: 1,
|
|
59
|
+
limit: (_d = defaultParams.limit) != null ? _d : 10,
|
|
60
|
+
totalPages: 0,
|
|
61
|
+
totalDocuments: 0
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
[queryKeyPrefix]: items,
|
|
65
|
+
pagination,
|
|
66
|
+
[`is${capPrefix}Loading`]: query.isLoading || query.isFetching,
|
|
67
|
+
[`${queryKeyPrefix}Error`]: query.error,
|
|
68
|
+
[`invalidate${capPrefix}`]: () => queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] })
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
// -------------------------------------------------------------------------
|
|
72
|
+
// useGet — single item by id
|
|
73
|
+
// -------------------------------------------------------------------------
|
|
74
|
+
useGet: (id, staleTime = 3e4) => {
|
|
75
|
+
const query = (0, import_react_query.useQuery)({
|
|
76
|
+
queryKey: [queryKeyPrefix, id],
|
|
77
|
+
queryFn: async () => {
|
|
78
|
+
const raw = await apiService.get(id);
|
|
79
|
+
return adapters.fromSingle(raw);
|
|
80
|
+
},
|
|
81
|
+
enabled: id !== void 0 && id !== null && id !== "",
|
|
82
|
+
staleTime
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
data: query.data,
|
|
86
|
+
isLoading: query.isLoading || query.isFetching,
|
|
87
|
+
error: query.error,
|
|
88
|
+
refetch: query.refetch
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
// -------------------------------------------------------------------------
|
|
92
|
+
// useMutations — create / update / delete with auto-invalidation
|
|
93
|
+
// -------------------------------------------------------------------------
|
|
94
|
+
useMutations: () => {
|
|
95
|
+
const queryClient = (0, import_react_query.useQueryClient)();
|
|
96
|
+
const invalidate = () => queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] });
|
|
97
|
+
const createMutation = (0, import_react_query.useMutation)({
|
|
98
|
+
mutationFn: async (payload) => {
|
|
99
|
+
const raw = await apiService.create(payload);
|
|
100
|
+
return adapters.fromSingle(raw);
|
|
101
|
+
},
|
|
102
|
+
onSuccess: invalidate
|
|
103
|
+
});
|
|
104
|
+
const updateMutation = (0, import_react_query.useMutation)({
|
|
105
|
+
mutationFn: async ({ _id, payload }) => {
|
|
106
|
+
const raw = await apiService.update(_id, payload);
|
|
107
|
+
return adapters.fromSingle(raw);
|
|
108
|
+
},
|
|
109
|
+
onSuccess: invalidate
|
|
110
|
+
});
|
|
111
|
+
const deleteMutation = (0, import_react_query.useMutation)({
|
|
112
|
+
mutationFn: async (_id) => {
|
|
113
|
+
const raw = await apiService.delete(_id);
|
|
114
|
+
return adapters.fromSingle(raw);
|
|
115
|
+
},
|
|
116
|
+
onSuccess: invalidate
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
create: createMutation,
|
|
120
|
+
update: updateMutation,
|
|
121
|
+
delete: deleteMutation
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
// -------------------------------------------------------------------------
|
|
125
|
+
// useInfinite — infinite scroll / load more
|
|
126
|
+
// -------------------------------------------------------------------------
|
|
127
|
+
useInfinite: (params = defaultParams) => {
|
|
128
|
+
return (0, import_react_query.useInfiniteQuery)({
|
|
129
|
+
queryKey: [queryKeyPrefix, "INFINITE", params],
|
|
130
|
+
queryFn: async ({ pageParam }) => {
|
|
131
|
+
var _a;
|
|
132
|
+
const raw = await apiService.list({
|
|
133
|
+
...params,
|
|
134
|
+
page: pageParam,
|
|
135
|
+
limit: (_a = params.limit) != null ? _a : 20
|
|
136
|
+
});
|
|
137
|
+
return adapters.fromList(raw);
|
|
138
|
+
},
|
|
139
|
+
getNextPageParam: (lastPage) => {
|
|
140
|
+
const { page, totalPages } = lastPage.pagination;
|
|
141
|
+
return page < totalPages ? page + 1 : void 0;
|
|
142
|
+
},
|
|
143
|
+
initialPageParam: 1
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
149
|
+
0 && (module.exports = {
|
|
150
|
+
createResourceHooks
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/hooks/createResourceHooks.ts"],"sourcesContent":["export { createResourceHooks } from \"./hooks/createResourceHooks\";\nexport type {\n UseListReturn,\n CreateResourceHooksOptions,\n} from \"./hooks/createResourceHooks\";\n","import {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n} from \"@tanstack/react-query\";\nimport type { ResourceService } from \"@void-snippets/client\";\nimport type {\n ResourceAdapters,\n ResourceListResult,\n TPagination,\n TQueryParams,\n TDefaultPaginatedResponse,\n TDefaultSingleResponse,\n} from \"@void-snippets/core\";\nimport { createDefaultAdapters } from \"@void-snippets/core\";\n\n// ============================================================================\n// TYPE HELPERS\n// ============================================================================\n\ntype Capitalize<S extends string> = S extends `${infer F}${infer Rest}`\n ? `${Uppercase<F>}${Rest}`\n : S;\n\nconst DEFAULT_PAGINATION: Required<TQueryParams> = {\n page: 1,\n limit: 10,\n};\n\n// ============================================================================\n// RETURN TYPE — useList\n// Dynamically named keys based on the queryKeyPrefix (e.g. \"contacts\"):\n// { contacts: TBase[], isContactsLoading: boolean, contactsError: Error | null, invalidateContacts: () => void }\n// ============================================================================\n\nexport type UseListReturn<K extends string, TBase> = {\n [P in K]: TBase[];\n} & {\n pagination: TPagination;\n} & {\n [P in `is${Capitalize<K>}Loading`]: boolean;\n} & {\n [P in `${K}Error`]: Error | null;\n} & {\n [P in `invalidate${Capitalize<K>}`]: () => void;\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport interface CreateResourceHooksOptions<\n TListRaw,\n TBase,\n TSingleRaw,\n TDetail\n> {\n /**\n * Adapters let you map your API's raw response shapes to the library's\n * internal format. If your API matches the default shape\n * ({ data: { items, page, limit, totalPages, totalDocuments } })\n * you can omit this entirely.\n *\n * @example\n * createResourceHooks(\"contacts\", ContactsApis, {\n * adapters: {\n * fromList: (raw) => ({\n * items: raw.results,\n * pagination: { page: raw.page, limit: raw.perPage, totalPages: raw.pages, totalDocuments: raw.total },\n * }),\n * fromSingle: (raw) => raw.payload,\n * }\n * })\n */\n adapters?: ResourceAdapters<TListRaw, TBase, TSingleRaw, TDetail>;\n\n /**\n * Default params for useList and useInfinite.\n * @default { page: 1, limit: 10 }\n */\n defaultParams?: TQueryParams;\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\n/**\n * Creates a set of TanStack Query hooks for a resource.\n *\n * @param queryKeyPrefix - Used as the TanStack Query cache key prefix AND\n * to name the returned hook properties dynamically.\n * e.g. \"contacts\" → { contacts, isContactsLoading, ... }\n * @param apiService - An instance of ResourceService (or a subclass).\n * @param options - Optional adapters and default params.\n *\n * @example\n * // contacts.hooks.ts\n * import { createResourceHooks } from '@void-snippets/react';\n * import { ContactsApis } from './contacts.api';\n *\n * export const contactHooks = createResourceHooks('contacts', ContactsApis);\n *\n * // In a component:\n * const { contacts, isContactsLoading } = contactHooks.useList();\n * const { data } = contactHooks.useGet(id);\n * const { create, update, delete: deleteContact } = contactHooks.useMutations();\n */\nexport function createResourceHooks<\n K extends string,\n TId,\n TBase,\n TDetail = TBase,\n TCreate = Partial<TBase>,\n TUpdate = Partial<TBase>,\n TListRaw = TDefaultPaginatedResponse<TBase>,\n TSingleRaw = TDefaultSingleResponse<TDetail>\n>(\n queryKeyPrefix: K,\n apiService: ResourceService<TId, TBase, TDetail, TCreate, TUpdate, TListRaw, TSingleRaw>,\n options: CreateResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail> = {}\n) {\n const {\n adapters = createDefaultAdapters<TBase, TDetail>() as unknown as ResourceAdapters<TListRaw, TBase, TSingleRaw, TDetail>,\n defaultParams = DEFAULT_PAGINATION,\n } = options;\n\n const capitalize = (str: string) =>\n str.charAt(0).toUpperCase() + str.slice(1);\n const capPrefix = capitalize(queryKeyPrefix);\n\n return {\n\n // -------------------------------------------------------------------------\n // useList — paginated list with invalidation helper\n // -------------------------------------------------------------------------\n useList: (\n params: TQueryParams = defaultParams\n ): UseListReturn<K, TBase> => {\n const queryClient = useQueryClient();\n const queryKey = [queryKeyPrefix, params];\n\n const query = useQuery<ResourceListResult<TBase>, Error>({\n queryKey,\n queryFn: async () => {\n const raw = await apiService.list(params);\n return adapters.fromList(raw as TListRaw);\n },\n });\n\n const items = query.data?.items ?? [];\n const pagination: TPagination = query.data?.pagination ?? {\n page: 1,\n limit: defaultParams.limit ?? 10,\n totalPages: 0,\n totalDocuments: 0,\n };\n\n return {\n [queryKeyPrefix]: items,\n pagination,\n [`is${capPrefix}Loading`]: query.isLoading || query.isFetching,\n [`${queryKeyPrefix}Error`]: query.error,\n [`invalidate${capPrefix}`]: () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] }),\n } as UseListReturn<K, TBase>;\n },\n\n // -------------------------------------------------------------------------\n // useGet — single item by id\n // -------------------------------------------------------------------------\n useGet: (id: TId, staleTime = 30_000) => {\n const query = useQuery<TDetail, Error>({\n queryKey: [queryKeyPrefix, id],\n queryFn: async () => {\n const raw = await apiService.get(id);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n enabled: id !== undefined && id !== null && id !== \"\",\n staleTime,\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading || query.isFetching,\n error: query.error,\n refetch: query.refetch,\n };\n },\n\n // -------------------------------------------------------------------------\n // useMutations — create / update / delete with auto-invalidation\n // -------------------------------------------------------------------------\n useMutations: () => {\n const queryClient = useQueryClient();\n const invalidate = () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] });\n\n const createMutation = useMutation<TDetail, Error, TCreate>({\n mutationFn: async (payload) => {\n const raw = await apiService.create(payload);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n onSuccess: invalidate,\n });\n\n const updateMutation = useMutation<\n TDetail,\n Error,\n { _id: TId; payload: TUpdate }\n >({\n mutationFn: async ({ _id, payload }) => {\n const raw = await apiService.update(_id, payload);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n onSuccess: invalidate,\n });\n\n const deleteMutation = useMutation<TDetail, Error, TId>({\n mutationFn: async (_id) => {\n const raw = await apiService.delete(_id);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n onSuccess: invalidate,\n });\n\n return {\n create: createMutation,\n update: updateMutation,\n delete: deleteMutation,\n };\n },\n\n // -------------------------------------------------------------------------\n // useInfinite — infinite scroll / load more\n // -------------------------------------------------------------------------\n useInfinite: (params: TQueryParams = defaultParams) => {\n return useInfiniteQuery<ResourceListResult<TBase>, Error>({\n queryKey: [queryKeyPrefix, \"INFINITE\", params],\n queryFn: async ({ pageParam }) => {\n const raw = await apiService.list({\n ...params,\n page: pageParam as number,\n limit: params.limit ?? 20,\n });\n return adapters.fromList(raw as TListRaw);\n },\n getNextPageParam: (lastPage) => {\n const { page, totalPages } = lastPage.pagination;\n return page < totalPages ? page + 1 : undefined;\n },\n initialPageParam: 1,\n });\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,yBAKO;AAUP,kBAAsC;AAUtC,IAAM,qBAA6C;AAAA,EACjD,MAAM;AAAA,EACN,OAAO;AACT;AAiFO,SAAS,oBAUd,gBACA,YACA,UAA4E,CAAC,GAC7E;AACA,QAAM;AAAA,IACJ,eAAW,mCAAsC;AAAA,IACjD,gBAAgB;AAAA,EAClB,IAAI;AAEJ,QAAM,aAAa,CAAC,QAClB,IAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC;AAC3C,QAAM,YAAY,WAAW,cAAc;AAE3C,SAAO;AAAA;AAAA;AAAA;AAAA,IAKL,SAAS,CACP,SAAuB,kBACK;AA3IlC;AA4IM,YAAM,kBAAc,mCAAe;AACnC,YAAM,WAAW,CAAC,gBAAgB,MAAM;AAExC,YAAM,YAAQ,6BAA2C;AAAA,QACvD;AAAA,QACA,SAAS,YAAY;AACnB,gBAAM,MAAM,MAAM,WAAW,KAAK,MAAM;AACxC,iBAAO,SAAS,SAAS,GAAe;AAAA,QAC1C;AAAA,MACF,CAAC;AAED,YAAM,SAAQ,iBAAM,SAAN,mBAAY,UAAZ,YAAqB,CAAC;AACpC,YAAM,cAA0B,iBAAM,SAAN,mBAAY,eAAZ,YAA0B;AAAA,QACxD,MAAM;AAAA,QACN,QAAO,mBAAc,UAAd,YAAuB;AAAA,QAC9B,YAAY;AAAA,QACZ,gBAAgB;AAAA,MAClB;AAEA,aAAO;AAAA,QACL,CAAC,cAAc,GAAG;AAAA,QAClB;AAAA,QACA,CAAC,KAAK,SAAS,SAAS,GAAG,MAAM,aAAa,MAAM;AAAA,QACpD,CAAC,GAAG,cAAc,OAAO,GAAG,MAAM;AAAA,QAClC,CAAC,aAAa,SAAS,EAAE,GAAG,MAC1B,YAAY,kBAAkB,EAAE,UAAU,CAAC,cAAc,EAAE,CAAC;AAAA,MAChE;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,QAAQ,CAAC,IAAS,YAAY,QAAW;AACvC,YAAM,YAAQ,6BAAyB;AAAA,QACrC,UAAU,CAAC,gBAAgB,EAAE;AAAA,QAC7B,SAAS,YAAY;AACnB,gBAAM,MAAM,MAAM,WAAW,IAAI,EAAE;AACnC,iBAAO,SAAS,WAAW,GAAiB;AAAA,QAC9C;AAAA,QACA,SAAS,OAAO,UAAa,OAAO,QAAQ,OAAO;AAAA,QACnD;AAAA,MACF,CAAC;AAED,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,WAAW,MAAM,aAAa,MAAM;AAAA,QACpC,OAAO,MAAM;AAAA,QACb,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,cAAc,MAAM;AAClB,YAAM,kBAAc,mCAAe;AACnC,YAAM,aAAa,MACjB,YAAY,kBAAkB,EAAE,UAAU,CAAC,cAAc,EAAE,CAAC;AAE9D,YAAM,qBAAiB,gCAAqC;AAAA,QAC1D,YAAY,OAAO,YAAY;AAC7B,gBAAM,MAAM,MAAM,WAAW,OAAO,OAAO;AAC3C,iBAAO,SAAS,WAAW,GAAiB;AAAA,QAC9C;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAED,YAAM,qBAAiB,gCAIrB;AAAA,QACA,YAAY,OAAO,EAAE,KAAK,QAAQ,MAAM;AACtC,gBAAM,MAAM,MAAM,WAAW,OAAO,KAAK,OAAO;AAChD,iBAAO,SAAS,WAAW,GAAiB;AAAA,QAC9C;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAED,YAAM,qBAAiB,gCAAiC;AAAA,QACtD,YAAY,OAAO,QAAQ;AACzB,gBAAM,MAAM,MAAM,WAAW,OAAO,GAAG;AACvC,iBAAO,SAAS,WAAW,GAAiB;AAAA,QAC9C;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAED,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,aAAa,CAAC,SAAuB,kBAAkB;AACrD,iBAAO,qCAAmD;AAAA,QACxD,UAAU,CAAC,gBAAgB,YAAY,MAAM;AAAA,QAC7C,SAAS,OAAO,EAAE,UAAU,MAAM;AAhP1C;AAiPU,gBAAM,MAAM,MAAM,WAAW,KAAK;AAAA,YAChC,GAAG;AAAA,YACH,MAAM;AAAA,YACN,QAAO,YAAO,UAAP,YAAgB;AAAA,UACzB,CAAC;AACD,iBAAO,SAAS,SAAS,GAAe;AAAA,QAC1C;AAAA,QACA,kBAAkB,CAAC,aAAa;AAC9B,gBAAM,EAAE,MAAM,WAAW,IAAI,SAAS;AACtC,iBAAO,OAAO,aAAa,OAAO,IAAI;AAAA,QACxC;AAAA,QACA,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// src/hooks/createResourceHooks.ts
|
|
2
|
+
import {
|
|
3
|
+
useInfiniteQuery,
|
|
4
|
+
useMutation,
|
|
5
|
+
useQuery,
|
|
6
|
+
useQueryClient
|
|
7
|
+
} from "@tanstack/react-query";
|
|
8
|
+
import { createDefaultAdapters } from "@void-snippets/core";
|
|
9
|
+
var DEFAULT_PAGINATION = {
|
|
10
|
+
page: 1,
|
|
11
|
+
limit: 10
|
|
12
|
+
};
|
|
13
|
+
function createResourceHooks(queryKeyPrefix, apiService, options = {}) {
|
|
14
|
+
const {
|
|
15
|
+
adapters = createDefaultAdapters(),
|
|
16
|
+
defaultParams = DEFAULT_PAGINATION
|
|
17
|
+
} = options;
|
|
18
|
+
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
19
|
+
const capPrefix = capitalize(queryKeyPrefix);
|
|
20
|
+
return {
|
|
21
|
+
// -------------------------------------------------------------------------
|
|
22
|
+
// useList — paginated list with invalidation helper
|
|
23
|
+
// -------------------------------------------------------------------------
|
|
24
|
+
useList: (params = defaultParams) => {
|
|
25
|
+
var _a, _b, _c, _d, _e;
|
|
26
|
+
const queryClient = useQueryClient();
|
|
27
|
+
const queryKey = [queryKeyPrefix, params];
|
|
28
|
+
const query = useQuery({
|
|
29
|
+
queryKey,
|
|
30
|
+
queryFn: async () => {
|
|
31
|
+
const raw = await apiService.list(params);
|
|
32
|
+
return adapters.fromList(raw);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const items = (_b = (_a = query.data) == null ? void 0 : _a.items) != null ? _b : [];
|
|
36
|
+
const pagination = (_e = (_c = query.data) == null ? void 0 : _c.pagination) != null ? _e : {
|
|
37
|
+
page: 1,
|
|
38
|
+
limit: (_d = defaultParams.limit) != null ? _d : 10,
|
|
39
|
+
totalPages: 0,
|
|
40
|
+
totalDocuments: 0
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
[queryKeyPrefix]: items,
|
|
44
|
+
pagination,
|
|
45
|
+
[`is${capPrefix}Loading`]: query.isLoading || query.isFetching,
|
|
46
|
+
[`${queryKeyPrefix}Error`]: query.error,
|
|
47
|
+
[`invalidate${capPrefix}`]: () => queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] })
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
// -------------------------------------------------------------------------
|
|
51
|
+
// useGet — single item by id
|
|
52
|
+
// -------------------------------------------------------------------------
|
|
53
|
+
useGet: (id, staleTime = 3e4) => {
|
|
54
|
+
const query = useQuery({
|
|
55
|
+
queryKey: [queryKeyPrefix, id],
|
|
56
|
+
queryFn: async () => {
|
|
57
|
+
const raw = await apiService.get(id);
|
|
58
|
+
return adapters.fromSingle(raw);
|
|
59
|
+
},
|
|
60
|
+
enabled: id !== void 0 && id !== null && id !== "",
|
|
61
|
+
staleTime
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
data: query.data,
|
|
65
|
+
isLoading: query.isLoading || query.isFetching,
|
|
66
|
+
error: query.error,
|
|
67
|
+
refetch: query.refetch
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
// -------------------------------------------------------------------------
|
|
71
|
+
// useMutations — create / update / delete with auto-invalidation
|
|
72
|
+
// -------------------------------------------------------------------------
|
|
73
|
+
useMutations: () => {
|
|
74
|
+
const queryClient = useQueryClient();
|
|
75
|
+
const invalidate = () => queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] });
|
|
76
|
+
const createMutation = useMutation({
|
|
77
|
+
mutationFn: async (payload) => {
|
|
78
|
+
const raw = await apiService.create(payload);
|
|
79
|
+
return adapters.fromSingle(raw);
|
|
80
|
+
},
|
|
81
|
+
onSuccess: invalidate
|
|
82
|
+
});
|
|
83
|
+
const updateMutation = useMutation({
|
|
84
|
+
mutationFn: async ({ _id, payload }) => {
|
|
85
|
+
const raw = await apiService.update(_id, payload);
|
|
86
|
+
return adapters.fromSingle(raw);
|
|
87
|
+
},
|
|
88
|
+
onSuccess: invalidate
|
|
89
|
+
});
|
|
90
|
+
const deleteMutation = useMutation({
|
|
91
|
+
mutationFn: async (_id) => {
|
|
92
|
+
const raw = await apiService.delete(_id);
|
|
93
|
+
return adapters.fromSingle(raw);
|
|
94
|
+
},
|
|
95
|
+
onSuccess: invalidate
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
create: createMutation,
|
|
99
|
+
update: updateMutation,
|
|
100
|
+
delete: deleteMutation
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
// -------------------------------------------------------------------------
|
|
104
|
+
// useInfinite — infinite scroll / load more
|
|
105
|
+
// -------------------------------------------------------------------------
|
|
106
|
+
useInfinite: (params = defaultParams) => {
|
|
107
|
+
return useInfiniteQuery({
|
|
108
|
+
queryKey: [queryKeyPrefix, "INFINITE", params],
|
|
109
|
+
queryFn: async ({ pageParam }) => {
|
|
110
|
+
var _a;
|
|
111
|
+
const raw = await apiService.list({
|
|
112
|
+
...params,
|
|
113
|
+
page: pageParam,
|
|
114
|
+
limit: (_a = params.limit) != null ? _a : 20
|
|
115
|
+
});
|
|
116
|
+
return adapters.fromList(raw);
|
|
117
|
+
},
|
|
118
|
+
getNextPageParam: (lastPage) => {
|
|
119
|
+
const { page, totalPages } = lastPage.pagination;
|
|
120
|
+
return page < totalPages ? page + 1 : void 0;
|
|
121
|
+
},
|
|
122
|
+
initialPageParam: 1
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
createResourceHooks
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/createResourceHooks.ts"],"sourcesContent":["import {\n useInfiniteQuery,\n useMutation,\n useQuery,\n useQueryClient,\n} from \"@tanstack/react-query\";\nimport type { ResourceService } from \"@void-snippets/client\";\nimport type {\n ResourceAdapters,\n ResourceListResult,\n TPagination,\n TQueryParams,\n TDefaultPaginatedResponse,\n TDefaultSingleResponse,\n} from \"@void-snippets/core\";\nimport { createDefaultAdapters } from \"@void-snippets/core\";\n\n// ============================================================================\n// TYPE HELPERS\n// ============================================================================\n\ntype Capitalize<S extends string> = S extends `${infer F}${infer Rest}`\n ? `${Uppercase<F>}${Rest}`\n : S;\n\nconst DEFAULT_PAGINATION: Required<TQueryParams> = {\n page: 1,\n limit: 10,\n};\n\n// ============================================================================\n// RETURN TYPE — useList\n// Dynamically named keys based on the queryKeyPrefix (e.g. \"contacts\"):\n// { contacts: TBase[], isContactsLoading: boolean, contactsError: Error | null, invalidateContacts: () => void }\n// ============================================================================\n\nexport type UseListReturn<K extends string, TBase> = {\n [P in K]: TBase[];\n} & {\n pagination: TPagination;\n} & {\n [P in `is${Capitalize<K>}Loading`]: boolean;\n} & {\n [P in `${K}Error`]: Error | null;\n} & {\n [P in `invalidate${Capitalize<K>}`]: () => void;\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport interface CreateResourceHooksOptions<\n TListRaw,\n TBase,\n TSingleRaw,\n TDetail\n> {\n /**\n * Adapters let you map your API's raw response shapes to the library's\n * internal format. If your API matches the default shape\n * ({ data: { items, page, limit, totalPages, totalDocuments } })\n * you can omit this entirely.\n *\n * @example\n * createResourceHooks(\"contacts\", ContactsApis, {\n * adapters: {\n * fromList: (raw) => ({\n * items: raw.results,\n * pagination: { page: raw.page, limit: raw.perPage, totalPages: raw.pages, totalDocuments: raw.total },\n * }),\n * fromSingle: (raw) => raw.payload,\n * }\n * })\n */\n adapters?: ResourceAdapters<TListRaw, TBase, TSingleRaw, TDetail>;\n\n /**\n * Default params for useList and useInfinite.\n * @default { page: 1, limit: 10 }\n */\n defaultParams?: TQueryParams;\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\n/**\n * Creates a set of TanStack Query hooks for a resource.\n *\n * @param queryKeyPrefix - Used as the TanStack Query cache key prefix AND\n * to name the returned hook properties dynamically.\n * e.g. \"contacts\" → { contacts, isContactsLoading, ... }\n * @param apiService - An instance of ResourceService (or a subclass).\n * @param options - Optional adapters and default params.\n *\n * @example\n * // contacts.hooks.ts\n * import { createResourceHooks } from '@void-snippets/react';\n * import { ContactsApis } from './contacts.api';\n *\n * export const contactHooks = createResourceHooks('contacts', ContactsApis);\n *\n * // In a component:\n * const { contacts, isContactsLoading } = contactHooks.useList();\n * const { data } = contactHooks.useGet(id);\n * const { create, update, delete: deleteContact } = contactHooks.useMutations();\n */\nexport function createResourceHooks<\n K extends string,\n TId,\n TBase,\n TDetail = TBase,\n TCreate = Partial<TBase>,\n TUpdate = Partial<TBase>,\n TListRaw = TDefaultPaginatedResponse<TBase>,\n TSingleRaw = TDefaultSingleResponse<TDetail>\n>(\n queryKeyPrefix: K,\n apiService: ResourceService<TId, TBase, TDetail, TCreate, TUpdate, TListRaw, TSingleRaw>,\n options: CreateResourceHooksOptions<TListRaw, TBase, TSingleRaw, TDetail> = {}\n) {\n const {\n adapters = createDefaultAdapters<TBase, TDetail>() as unknown as ResourceAdapters<TListRaw, TBase, TSingleRaw, TDetail>,\n defaultParams = DEFAULT_PAGINATION,\n } = options;\n\n const capitalize = (str: string) =>\n str.charAt(0).toUpperCase() + str.slice(1);\n const capPrefix = capitalize(queryKeyPrefix);\n\n return {\n\n // -------------------------------------------------------------------------\n // useList — paginated list with invalidation helper\n // -------------------------------------------------------------------------\n useList: (\n params: TQueryParams = defaultParams\n ): UseListReturn<K, TBase> => {\n const queryClient = useQueryClient();\n const queryKey = [queryKeyPrefix, params];\n\n const query = useQuery<ResourceListResult<TBase>, Error>({\n queryKey,\n queryFn: async () => {\n const raw = await apiService.list(params);\n return adapters.fromList(raw as TListRaw);\n },\n });\n\n const items = query.data?.items ?? [];\n const pagination: TPagination = query.data?.pagination ?? {\n page: 1,\n limit: defaultParams.limit ?? 10,\n totalPages: 0,\n totalDocuments: 0,\n };\n\n return {\n [queryKeyPrefix]: items,\n pagination,\n [`is${capPrefix}Loading`]: query.isLoading || query.isFetching,\n [`${queryKeyPrefix}Error`]: query.error,\n [`invalidate${capPrefix}`]: () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] }),\n } as UseListReturn<K, TBase>;\n },\n\n // -------------------------------------------------------------------------\n // useGet — single item by id\n // -------------------------------------------------------------------------\n useGet: (id: TId, staleTime = 30_000) => {\n const query = useQuery<TDetail, Error>({\n queryKey: [queryKeyPrefix, id],\n queryFn: async () => {\n const raw = await apiService.get(id);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n enabled: id !== undefined && id !== null && id !== \"\",\n staleTime,\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading || query.isFetching,\n error: query.error,\n refetch: query.refetch,\n };\n },\n\n // -------------------------------------------------------------------------\n // useMutations — create / update / delete with auto-invalidation\n // -------------------------------------------------------------------------\n useMutations: () => {\n const queryClient = useQueryClient();\n const invalidate = () =>\n queryClient.invalidateQueries({ queryKey: [queryKeyPrefix] });\n\n const createMutation = useMutation<TDetail, Error, TCreate>({\n mutationFn: async (payload) => {\n const raw = await apiService.create(payload);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n onSuccess: invalidate,\n });\n\n const updateMutation = useMutation<\n TDetail,\n Error,\n { _id: TId; payload: TUpdate }\n >({\n mutationFn: async ({ _id, payload }) => {\n const raw = await apiService.update(_id, payload);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n onSuccess: invalidate,\n });\n\n const deleteMutation = useMutation<TDetail, Error, TId>({\n mutationFn: async (_id) => {\n const raw = await apiService.delete(_id);\n return adapters.fromSingle(raw as TSingleRaw);\n },\n onSuccess: invalidate,\n });\n\n return {\n create: createMutation,\n update: updateMutation,\n delete: deleteMutation,\n };\n },\n\n // -------------------------------------------------------------------------\n // useInfinite — infinite scroll / load more\n // -------------------------------------------------------------------------\n useInfinite: (params: TQueryParams = defaultParams) => {\n return useInfiniteQuery<ResourceListResult<TBase>, Error>({\n queryKey: [queryKeyPrefix, \"INFINITE\", params],\n queryFn: async ({ pageParam }) => {\n const raw = await apiService.list({\n ...params,\n page: pageParam as number,\n limit: params.limit ?? 20,\n });\n return adapters.fromList(raw as TListRaw);\n },\n getNextPageParam: (lastPage) => {\n const { page, totalPages } = lastPage.pagination;\n return page < totalPages ? page + 1 : undefined;\n },\n initialPageParam: 1,\n });\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@void-snippets/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TanStack Query resource hooks factory for React",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"react",
|
|
19
|
+
"tanstack-query",
|
|
20
|
+
"react-query",
|
|
21
|
+
"hooks",
|
|
22
|
+
"api",
|
|
23
|
+
"void-snippets"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"react": ">=17.0.0"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@tanstack/react-query": "^5.0.0",
|
|
31
|
+
"@void-snippets/client": "0.1.0",
|
|
32
|
+
"@void-snippets/core": "0.1.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/react": "^18.0.0",
|
|
36
|
+
"react": "^18.0.0",
|
|
37
|
+
"tsup": "^8.0.0",
|
|
38
|
+
"typescript": "^5.4.0"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"dev": "tsup --watch"
|
|
43
|
+
}
|
|
44
|
+
}
|