@tpzdsp/next-toolkit 2.1.0 → 2.3.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 +23 -1
- package/package.json +7 -4
- package/src/http/query.ts +120 -3
package/README.md
CHANGED
|
@@ -559,10 +559,32 @@ import '@your-org/nextjs-library/src/assets/styles/globals.css';
|
|
|
559
559
|
4. Add tests for your changes (`src/test/YourComponent.test.tsx`)
|
|
560
560
|
5. Run the test suite (`pnpm test`)
|
|
561
561
|
6. Test with yalc in a real Next.js app
|
|
562
|
-
7. Commit your changes
|
|
562
|
+
7. Commit your changes following the [Angular commit message guidelines](https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md) — the `commit-msg` hook enforces this via commitlint
|
|
563
563
|
8. Push to the branch (`git push origin feature/amazing-feature`)
|
|
564
564
|
9. Open a Pull Request
|
|
565
565
|
|
|
566
|
+
### Commit Convention
|
|
567
|
+
|
|
568
|
+
We follow the [Angular commit message guidelines](https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md). Commits are validated by [commitlint](https://commitlint.io/) on every `git commit`. Allowed types come from `@commitlint/config-conventional`. Allowed scopes are defined in `commitlint.config.ts` — edit that file to add or remove scopes.
|
|
569
|
+
|
|
570
|
+
#### Smoke-testing the commit hook
|
|
571
|
+
|
|
572
|
+
Run these directly in the terminal to verify the hook is working after any changes to `commitlint.config.ts`:
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
# Should be rejected — wrong type
|
|
576
|
+
printf 'feature(map): bad type\n\nBody text here explaining the change.' | pnpm commitlint
|
|
577
|
+
|
|
578
|
+
# Should be rejected — unknown scope
|
|
579
|
+
printf 'feat(unknown): bad scope\n\nBody text here explaining the change.' | pnpm commitlint
|
|
580
|
+
|
|
581
|
+
# Should be rejected — missing body
|
|
582
|
+
printf 'feat(map): missing body\n' | pnpm commitlint
|
|
583
|
+
|
|
584
|
+
# Should pass
|
|
585
|
+
printf 'feat(map): valid message\n\nThis explains what changed and why.' | pnpm commitlint
|
|
586
|
+
```
|
|
587
|
+
|
|
566
588
|
### Code Style
|
|
567
589
|
|
|
568
590
|
- Use TypeScript for all files
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpzdsp/next-toolkit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "A reusable React component library for Next.js applications",
|
|
5
5
|
"packageManager": "pnpm@11.5.3",
|
|
6
6
|
"engines": {
|
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
11
|
"private": false,
|
|
12
|
-
"homepage": "https://github.com/
|
|
12
|
+
"homepage": "https://github.com/agrimetrics/next-toolkit#readme",
|
|
13
13
|
"author": "Mark Small",
|
|
14
14
|
"publishConfig": {
|
|
15
15
|
"access": "public"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/
|
|
19
|
+
"url": "git+https://github.com/agrimetrics/next-toolkit.git"
|
|
20
20
|
},
|
|
21
21
|
"bugs": {
|
|
22
|
-
"url": "https://github.com/
|
|
22
|
+
"url": "https://github.com/agrimetrics/next-toolkit/issues"
|
|
23
23
|
},
|
|
24
24
|
"main": "./src/index.ts",
|
|
25
25
|
"module": "./src/index.ts",
|
|
@@ -127,6 +127,9 @@
|
|
|
127
127
|
},
|
|
128
128
|
"devDependencies": {
|
|
129
129
|
"@better-fetch/fetch": "^1.1.21",
|
|
130
|
+
"@commitlint/cli": "^21.1.0",
|
|
131
|
+
"@commitlint/config-conventional": "^21.1.0",
|
|
132
|
+
"@commitlint/types": "^21.1.0",
|
|
130
133
|
"@floating-ui/react": "^0.27.17",
|
|
131
134
|
"@storybook/addon-docs": "10.3.5",
|
|
132
135
|
"@storybook/addon-links": "10.3.5",
|
package/src/http/query.ts
CHANGED
|
@@ -9,9 +9,12 @@ import {
|
|
|
9
9
|
type BetterFetchOption,
|
|
10
10
|
} from '@better-fetch/fetch';
|
|
11
11
|
import {
|
|
12
|
+
useMutation,
|
|
12
13
|
useQuery,
|
|
13
14
|
useSuspenseQuery,
|
|
14
15
|
type QueryKey,
|
|
16
|
+
type UseMutationOptions,
|
|
17
|
+
type UseMutationResult,
|
|
15
18
|
type UseQueryOptions,
|
|
16
19
|
type UseQueryResult,
|
|
17
20
|
type UseSuspenseQueryOptions,
|
|
@@ -84,8 +87,8 @@ type SchemaRoutesOf<Option extends CreateFetchOption> = Option extends {
|
|
|
84
87
|
? Routes
|
|
85
88
|
: undefined;
|
|
86
89
|
|
|
87
|
-
// We provide
|
|
88
|
-
type OmitReactQueryKeys = 'queryKey' | 'queryFn';
|
|
90
|
+
// We provide these keys automatically, so no need to let the user provide them.
|
|
91
|
+
type OmitReactQueryKeys = 'queryKey' | 'queryFn' | 'mutationFn' | 'mutationKey';
|
|
89
92
|
|
|
90
93
|
/**
|
|
91
94
|
* A higher-order type that creates React Query hooks (`useBetterQuerySafe` and `useBetterSuspenseQuery`)
|
|
@@ -183,6 +186,75 @@ type ReactQueryBetterFetch = <
|
|
|
183
186
|
OmitReactQueryKeys
|
|
184
187
|
>,
|
|
185
188
|
): UseSuspenseQueryResult<Output>;
|
|
189
|
+
|
|
190
|
+
// Mutation query (error thrown)
|
|
191
|
+
|
|
192
|
+
// Overload that uses schema output (`RoutesWithOutput`)
|
|
193
|
+
useBetterMutation<
|
|
194
|
+
Error = ApiError,
|
|
195
|
+
Route extends RoutesWithOutput<Routes> = RoutesWithOutput<Routes>,
|
|
196
|
+
>(
|
|
197
|
+
route: Route,
|
|
198
|
+
// If the route requires an input, then expect options that provide that input, otherwise just expect options without inputs.
|
|
199
|
+
fetchOptions?: OptionsNoInputOutput,
|
|
200
|
+
queryOptions?: Omit<
|
|
201
|
+
UseMutationOptions<SchemaRouteOutput<Routes, Route>, Error, unknown, unknown>,
|
|
202
|
+
OmitReactQueryKeys
|
|
203
|
+
>,
|
|
204
|
+
): UseMutationResult<
|
|
205
|
+
SchemaRouteOutput<Routes, Route>,
|
|
206
|
+
Error,
|
|
207
|
+
Route extends RoutesWithInput<Routes> ? OptionsWithInput<Routes, Route> : void
|
|
208
|
+
>;
|
|
209
|
+
|
|
210
|
+
// Overload that allows manual output type instead of schema (`RoutesWithoutOutput`)
|
|
211
|
+
useBetterMutation<
|
|
212
|
+
Output,
|
|
213
|
+
Error = ApiError,
|
|
214
|
+
Route extends RoutesWithoutOutput<Routes> = RoutesWithoutOutput<Routes>,
|
|
215
|
+
>(
|
|
216
|
+
route: Route,
|
|
217
|
+
fetchOptions?: OptionsNoInputOutput,
|
|
218
|
+
queryOptions?: Omit<UseMutationOptions<Output, Error, unknown, unknown>, OmitReactQueryKeys>,
|
|
219
|
+
): UseMutationResult<
|
|
220
|
+
Output,
|
|
221
|
+
Error,
|
|
222
|
+
Route extends RoutesWithInput<Routes> ? OptionsWithInput<Routes, Route> : void
|
|
223
|
+
>;
|
|
224
|
+
|
|
225
|
+
// Safe mutation (error NOT thrown)
|
|
226
|
+
|
|
227
|
+
// Overload that uses schema output (`RoutesWithOutput`)
|
|
228
|
+
useBetterMutationSafe<
|
|
229
|
+
Error = ApiError,
|
|
230
|
+
Route extends RoutesWithOutput<Routes> = RoutesWithOutput<Routes>,
|
|
231
|
+
>(
|
|
232
|
+
route: Route,
|
|
233
|
+
fetchOptions?: OptionsNoInputOutput,
|
|
234
|
+
queryOptions?: Omit<
|
|
235
|
+
UseMutationOptions<SchemaRouteOutput<Routes, Route>, Error, unknown, unknown>,
|
|
236
|
+
OmitReactQueryKeys
|
|
237
|
+
>,
|
|
238
|
+
): UseMutationResult<
|
|
239
|
+
SchemaRouteOutput<Routes, Route>,
|
|
240
|
+
Error,
|
|
241
|
+
Route extends RoutesWithInput<Routes> ? OptionsWithInput<Routes, Route> : void
|
|
242
|
+
>;
|
|
243
|
+
|
|
244
|
+
// Overload that allows manual output type instead of schema (`RoutesWithoutOutput`)
|
|
245
|
+
useBetterMutationSafe<
|
|
246
|
+
Output,
|
|
247
|
+
Error = ApiError,
|
|
248
|
+
Route extends RoutesWithoutOutput<Routes> = RoutesWithoutOutput<Routes>,
|
|
249
|
+
>(
|
|
250
|
+
route: Route,
|
|
251
|
+
fetchOptions?: OptionsNoInputOutput,
|
|
252
|
+
queryOptions?: Omit<UseMutationOptions<Output, Error, unknown, unknown>, OmitReactQueryKeys>,
|
|
253
|
+
): UseMutationResult<
|
|
254
|
+
Output,
|
|
255
|
+
Error,
|
|
256
|
+
Route extends RoutesWithInput<Routes> ? OptionsWithInput<Routes, Route> : void
|
|
257
|
+
>;
|
|
186
258
|
};
|
|
187
259
|
|
|
188
260
|
/**
|
|
@@ -283,5 +355,50 @@ export const reactQueryBetterFetch: ReactQueryBetterFetch = <
|
|
|
283
355
|
});
|
|
284
356
|
};
|
|
285
357
|
|
|
286
|
-
|
|
358
|
+
const useBetterMutation = <Route extends keyof Routes>(
|
|
359
|
+
route: Route,
|
|
360
|
+
fetchOptions?: InferOptions<FetchSchema, ''>,
|
|
361
|
+
queryOptions?: Omit<
|
|
362
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
363
|
+
UseMutationOptions<any, any, any, unknown>,
|
|
364
|
+
OmitReactQueryKeys | 'throwOnError'
|
|
365
|
+
>,
|
|
366
|
+
) => {
|
|
367
|
+
return useMutation({
|
|
368
|
+
...queryOptions,
|
|
369
|
+
mutationKey: [
|
|
370
|
+
route,
|
|
371
|
+
fetchOptions?.body,
|
|
372
|
+
fetchOptions?.params,
|
|
373
|
+
fetchOptions?.query,
|
|
374
|
+
fetchOptions?.headers,
|
|
375
|
+
],
|
|
376
|
+
mutationFn: (inputs) => anyInstance(route, { ...fetchOptions, ...inputs }),
|
|
377
|
+
throwOnError: true,
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const useBetterMutationSafe = <Route extends keyof Routes>(
|
|
382
|
+
route: Route,
|
|
383
|
+
fetchOptions?: InferOptions<FetchSchema, ''>,
|
|
384
|
+
queryOptions?: Omit<
|
|
385
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
386
|
+
UseMutationOptions<any, any, any, unknown>,
|
|
387
|
+
OmitReactQueryKeys | 'throwOnError'
|
|
388
|
+
>,
|
|
389
|
+
) => {
|
|
390
|
+
return useMutation({
|
|
391
|
+
...queryOptions,
|
|
392
|
+
mutationKey: [
|
|
393
|
+
route,
|
|
394
|
+
fetchOptions?.body,
|
|
395
|
+
fetchOptions?.params,
|
|
396
|
+
fetchOptions?.query,
|
|
397
|
+
fetchOptions?.headers,
|
|
398
|
+
],
|
|
399
|
+
mutationFn: (inputs) => anyInstance(route, { ...fetchOptions, ...inputs }),
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
return { useBetterQuerySafe, useBetterMutationSafe, useBetterMutation, useBetterSuspenseQuery };
|
|
287
404
|
};
|