@hirely/hooks 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.js ADDED
@@ -0,0 +1,535 @@
1
+ "use client";
2
+ import { createRequire } from "node:module";
3
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
+
5
+ // src/useFormHandler.ts
6
+ import { useState, useRef, useCallback, useMemo as useMemo2 } from "react";
7
+ import { useForm } from "react-hook-form";
8
+
9
+ // node_modules/@hookform/resolvers/dist/resolvers.mjs
10
+ import { get as e, set as r } from "react-hook-form";
11
+ var t = (r2, t2, s) => {
12
+ if (r2 && "reportValidity" in r2) {
13
+ const o = e(s, t2);
14
+ r2.setCustomValidity(o && o.message || ""), r2.reportValidity();
15
+ }
16
+ };
17
+ var s = (e2, r2) => {
18
+ for (const s2 in r2.fields) {
19
+ const o = r2.fields[s2];
20
+ o && o.ref && "reportValidity" in o.ref ? t(o.ref, s2, e2) : o && o.refs && o.refs.forEach((r3) => t(r3, s2, e2));
21
+ }
22
+ };
23
+ var o = (t2, o2) => {
24
+ o2.shouldUseNativeValidation && s(t2, o2);
25
+ const n = {};
26
+ for (const s2 in t2) {
27
+ const f = e(o2.fields, s2), c = Object.assign(t2[s2] || {}, { ref: f && f.refs ? f.refs[0] : f && f.ref });
28
+ if (i(o2.names || Object.keys(t2), s2)) {
29
+ const t3 = Object.assign({}, e(n, s2));
30
+ r(t3, "root", c), r(n, s2, t3);
31
+ } else
32
+ r(n, s2, c);
33
+ }
34
+ return n;
35
+ };
36
+ var i = (e2, r2) => {
37
+ const t2 = n(r2).replace(/[.*+?^${}()|\\]/g, "\\$&");
38
+ return e2.some((e3) => n(e3).match(`^${t2}\\.\\d+`));
39
+ };
40
+ function n(e2) {
41
+ return e2.replace(/\[(\d+)]/g, ".$1").replace(/[[\]]/g, "");
42
+ }
43
+
44
+ // node_modules/@hookform/resolvers/zod/dist/zod.mjs
45
+ import { appendErrors as n2 } from "react-hook-form";
46
+ function o2() {
47
+ return o2 = Object.assign ? Object.assign.bind() : function(r2) {
48
+ for (var e2 = 1;e2 < arguments.length; e2++) {
49
+ var n3 = arguments[e2];
50
+ for (var o3 in n3)
51
+ ({}).hasOwnProperty.call(n3, o3) && (r2[o3] = n3[o3]);
52
+ }
53
+ return r2;
54
+ }, o2.apply(null, arguments);
55
+ }
56
+ function t2(r2, e2) {
57
+ try {
58
+ var n3 = r2();
59
+ } catch (r3) {
60
+ return e2(r3);
61
+ }
62
+ return n3 && n3.then ? n3.then(undefined, e2) : n3;
63
+ }
64
+ function s2(r2, e2) {
65
+ for (var o3 = Object.create(null);r2.length; ) {
66
+ var t3 = r2[0], s3 = t3.code, i2 = t3.message, u = t3.path.join(".");
67
+ if (!o3[u])
68
+ if ("unionErrors" in t3) {
69
+ var a, c, l = t3.unionErrors.reduce(function(r3, e3) {
70
+ return e3.errors.length < r3.errors.length ? e3 : r3;
71
+ }).errors[0];
72
+ o3[u] = { message: (a = l == null ? undefined : l.message) != null ? a : i2, type: (c = l == null ? undefined : l.code) != null ? c : s3 };
73
+ } else
74
+ o3[u] = { message: i2, type: s3 };
75
+ if ("unionErrors" in t3 && t3.unionErrors.forEach(function(e3) {
76
+ return e3.errors.forEach(function(e4) {
77
+ return r2.push(e4);
78
+ });
79
+ }), e2) {
80
+ var f = o3[u].types, d = f && f[t3.code];
81
+ o3[u] = n2(u, e2, o3, s3, d ? [].concat(d, t3.message) : t3.message);
82
+ }
83
+ r2.shift();
84
+ }
85
+ return o3;
86
+ }
87
+ function i2(r2, e2) {
88
+ for (var t3 = Object.create(null), s3 = function() {
89
+ var s4 = r2[0], i3 = s4.code, u = s4.message, a = s4.path.join(".");
90
+ if (!t3[a])
91
+ if (s4.code === "invalid_union" && s4.errors.length > 0) {
92
+ var c, l, f = s4.errors.reduce(function(r3, e3) {
93
+ return e3.length < r3.length ? e3 : r3;
94
+ })[0];
95
+ t3[a] = { message: (c = f == null ? undefined : f.message) != null ? c : u, type: (l = f == null ? undefined : f.code) != null ? l : i3 };
96
+ } else
97
+ t3[a] = { message: u, type: i3 };
98
+ if (s4.code === "invalid_union" && s4.errors.forEach(function(e3) {
99
+ return e3.forEach(function(e4) {
100
+ return r2.push(o2({}, e4, { path: [].concat(s4.path, e4.path) }));
101
+ });
102
+ }), e2) {
103
+ var d = t3[a].types, h = d && d[s4.code];
104
+ t3[a] = n2(a, e2, t3, i3, h ? [].concat(h, s4.message) : s4.message);
105
+ }
106
+ r2.shift();
107
+ };r2.length; )
108
+ s3();
109
+ return t3;
110
+ }
111
+ function u(n3, o3, u2) {
112
+ if (u2 === undefined && (u2 = {}), function(r2) {
113
+ return "_zod" in r2 && typeof r2._zod == "object";
114
+ }(n3))
115
+ return function(s3, a, c) {
116
+ try {
117
+ return Promise.resolve(t2(function() {
118
+ function e2(e3) {
119
+ return c.shouldUseNativeValidation && s({}, c), { errors: {}, values: u2.raw ? Object.assign({}, s3) : e3 };
120
+ }
121
+ var t3 = n3;
122
+ return u2.mode === "sync" ? e2(t3.parse(s3, o3)) : Promise.resolve(t3.parseAsync(s3, o3)).then(e2);
123
+ }, function(r2) {
124
+ if (function(r3) {
125
+ var e2;
126
+ return !(r3 == null || (e2 = r3._zod) == null || (e2 = e2.traits) == null || !e2.has("$ZodError"));
127
+ }(r2))
128
+ return { values: {}, errors: o(i2(r2.issues, !c.shouldUseNativeValidation && c.criteriaMode === "all"), c) };
129
+ throw r2;
130
+ }));
131
+ } catch (r2) {
132
+ return Promise.reject(r2);
133
+ }
134
+ };
135
+ if (function(r2) {
136
+ return "_def" in r2 && typeof r2._def == "object";
137
+ }(n3))
138
+ return function(i3, a, c) {
139
+ try {
140
+ return Promise.resolve(t2(function() {
141
+ return Promise.resolve(n3[u2.mode === "sync" ? "parse" : "parseAsync"](i3, o3)).then(function(e2) {
142
+ return c.shouldUseNativeValidation && s({}, c), { errors: {}, values: u2.raw ? Object.assign({}, i3) : e2 };
143
+ });
144
+ }, function(r2) {
145
+ if (function(r3) {
146
+ return Array.isArray(r3 == null ? undefined : r3.issues);
147
+ }(r2))
148
+ return { values: {}, errors: o(s2(r2.errors, !c.shouldUseNativeValidation && c.criteriaMode === "all"), c) };
149
+ throw r2;
150
+ }));
151
+ } catch (r2) {
152
+ return Promise.reject(r2);
153
+ }
154
+ };
155
+ throw new Error("Invalid input: not a Zod schema");
156
+ }
157
+
158
+ // src/context.tsx
159
+ import { createContext, useContext, useMemo } from "react";
160
+ import { jsx } from "react/jsx-runtime";
161
+ "use client";
162
+ var FormHandlerContext = createContext({});
163
+ var FormHandlerProvider = ({
164
+ children,
165
+ defaultOptions
166
+ }) => {
167
+ const value = useMemo(() => defaultOptions, [defaultOptions]);
168
+ return /* @__PURE__ */ jsx(FormHandlerContext.Provider, {
169
+ value,
170
+ children
171
+ });
172
+ };
173
+ var useFormHandlerContext = () => useContext(FormHandlerContext);
174
+
175
+ // src/useFormHandler.ts
176
+ "use client";
177
+ var defaultParseResponse = (res) => ({
178
+ success: res?.success !== undefined ? Boolean(res.success) : true,
179
+ message: res?.message,
180
+ data: res
181
+ });
182
+ var defaultParseError = (err) => {
183
+ let message = "Request failed";
184
+ if (err?.isAxiosError) {
185
+ message = err?.response?.data?.message || err.message || message;
186
+ if (err.code === "ERR_CANCELED") {
187
+ message = "Request was cancelled";
188
+ }
189
+ } else if (err instanceof Error) {
190
+ message = err.message;
191
+ }
192
+ return { message };
193
+ };
194
+ var cachedAxios = null;
195
+ var axiosLoadPromise = null;
196
+ var getAxios = async () => {
197
+ if (cachedAxios)
198
+ return cachedAxios;
199
+ if (!axiosLoadPromise) {
200
+ axiosLoadPromise = import("axios").then((m) => {
201
+ cachedAxios = m.default || m;
202
+ return cachedAxios;
203
+ }).catch(() => {
204
+ axiosLoadPromise = null;
205
+ return null;
206
+ });
207
+ }
208
+ return axiosLoadPromise;
209
+ };
210
+ var cachedSonnerToast = null;
211
+ var sonnerLoadPromise = null;
212
+ var getSonnerToast = async () => {
213
+ if (cachedSonnerToast)
214
+ return cachedSonnerToast;
215
+ if (!sonnerLoadPromise) {
216
+ sonnerLoadPromise = import("sonner").then((m) => {
217
+ cachedSonnerToast = m.toast || m;
218
+ return cachedSonnerToast;
219
+ }).catch(() => {
220
+ sonnerLoadPromise = null;
221
+ return null;
222
+ });
223
+ }
224
+ return sonnerLoadPromise;
225
+ };
226
+ function useFormHandlerInternal(options) {
227
+ const optionsRef = useRef(options);
228
+ optionsRef.current = options;
229
+ const {
230
+ schema,
231
+ defaultValues,
232
+ values,
233
+ mode = "onSubmit",
234
+ reValidateMode = "onChange"
235
+ } = options;
236
+ const [loading, setLoading] = useState(false);
237
+ const [error, setError] = useState(null);
238
+ const abortControllerRef = useRef(null);
239
+ const form = useForm({
240
+ resolver: u(schema),
241
+ defaultValues,
242
+ values,
243
+ mode,
244
+ reValidateMode
245
+ });
246
+ const abort = useCallback(() => {
247
+ if (abortControllerRef.current) {
248
+ abortControllerRef.current.abort();
249
+ abortControllerRef.current = null;
250
+ }
251
+ }, []);
252
+ const submitHandler = useCallback(async (data) => {
253
+ const currentOptions = optionsRef.current;
254
+ const {
255
+ endpoint,
256
+ method = "post",
257
+ service,
258
+ transformData,
259
+ onMutate,
260
+ onSuccess,
261
+ onError,
262
+ onSubmitStart,
263
+ onSubmitEnd,
264
+ notify,
265
+ resetOptions = { resetAfterSuccess: true, keepDefaultValues: true },
266
+ useFormData = false,
267
+ enableAbort = false,
268
+ axiosConfig = {},
269
+ parseResponse = defaultParseResponse,
270
+ parseError = defaultParseError
271
+ } = currentOptions;
272
+ let context;
273
+ const transformedData = transformData ? transformData(data) : data;
274
+ let notifyFn;
275
+ if (notify) {
276
+ notifyFn = notify;
277
+ } else {
278
+ const toast = await getSonnerToast();
279
+ if (toast) {
280
+ notifyFn = (message, type) => {
281
+ if (type === "success") {
282
+ toast.success(message);
283
+ } else {
284
+ toast.error(message);
285
+ }
286
+ };
287
+ } else {
288
+ notifyFn = () => {};
289
+ }
290
+ }
291
+ if (enableAbort) {
292
+ abortControllerRef.current = new AbortController;
293
+ }
294
+ try {
295
+ setLoading(true);
296
+ setError(null);
297
+ onSubmitStart?.();
298
+ if (onMutate) {
299
+ context = await onMutate(data);
300
+ }
301
+ let responseData;
302
+ let payload = transformedData;
303
+ if (useFormData) {
304
+ const formData = new FormData;
305
+ if (transformedData && typeof transformedData === "object") {
306
+ for (const [key, value] of Object.entries(transformedData)) {
307
+ if (value instanceof File || value instanceof Blob) {
308
+ formData.append(key, value);
309
+ } else if (Array.isArray(value)) {
310
+ for (const item of value) {
311
+ if (item instanceof File || item instanceof Blob) {
312
+ formData.append(key, item);
313
+ } else if (item !== undefined && item !== null) {
314
+ formData.append(key, String(item));
315
+ }
316
+ }
317
+ } else if (value !== undefined && value !== null) {
318
+ formData.append(key, String(value));
319
+ }
320
+ }
321
+ }
322
+ payload = formData;
323
+ }
324
+ if (service) {
325
+ responseData = await service(payload);
326
+ } else {
327
+ if (!endpoint) {
328
+ throw new Error("No endpoint or service provided");
329
+ }
330
+ const axiosInstance = await getAxios();
331
+ if (!axiosInstance) {
332
+ throw new Error("axios is not installed. Please install axios or provide a custom `service` function.");
333
+ }
334
+ const config = {
335
+ method,
336
+ url: endpoint,
337
+ data: payload,
338
+ ...axiosConfig,
339
+ signal: enableAbort ? abortControllerRef.current?.signal : undefined,
340
+ headers: useFormData ? {
341
+ ...axiosConfig.headers,
342
+ "Content-Type": "multipart/form-data"
343
+ } : axiosConfig.headers
344
+ };
345
+ const res = await axiosInstance(config);
346
+ responseData = res.data;
347
+ }
348
+ const parsed = parseResponse(responseData);
349
+ const isSuccess = parsed.success;
350
+ const message = parsed.message || (isSuccess ? "Success" : "Something went wrong");
351
+ if (isSuccess) {
352
+ notifyFn(message, "success");
353
+ onSuccess?.(responseData, context);
354
+ if (resetOptions.resetAfterSuccess !== false) {
355
+ form.reset(undefined, {
356
+ keepDefaultValues: resetOptions.keepDefaultValues !== false,
357
+ keepDirty: resetOptions.keepDirty || false,
358
+ keepTouched: false,
359
+ keepErrors: false,
360
+ keepValues: false
361
+ });
362
+ }
363
+ } else {
364
+ notifyFn(message, "error");
365
+ onError?.(responseData, context);
366
+ setError(new Error(message));
367
+ }
368
+ } catch (err) {
369
+ const parsedError = parseError(err);
370
+ const errorMsg = parsedError.message;
371
+ setError(new Error(errorMsg));
372
+ notifyFn(errorMsg, "error");
373
+ onError?.(err, context);
374
+ } finally {
375
+ setLoading(false);
376
+ onSubmitEnd?.();
377
+ abortControllerRef.current = null;
378
+ }
379
+ }, [form]);
380
+ const onSubmit = useMemo2(() => form.handleSubmit(submitHandler), [form, submitHandler]);
381
+ return useMemo2(() => ({
382
+ ...form,
383
+ onSubmit,
384
+ loading,
385
+ error,
386
+ setError,
387
+ abort: options.enableAbort ? abort : undefined
388
+ }), [form, onSubmit, loading, error, setError, abort, options.enableAbort]);
389
+ }
390
+ function useFormHandler(options) {
391
+ const contextOptions = useFormHandlerContext();
392
+ const mergedOptions = useMemo2(() => {
393
+ return {
394
+ ...contextOptions,
395
+ ...options,
396
+ axiosConfig: {
397
+ ...contextOptions.axiosConfig || {},
398
+ ...options.axiosConfig || {}
399
+ },
400
+ resetOptions: {
401
+ ...contextOptions.resetOptions || {},
402
+ ...options.resetOptions || {}
403
+ }
404
+ };
405
+ }, [contextOptions, options]);
406
+ return useFormHandlerInternal(mergedOptions);
407
+ }
408
+ function createFormHandler(defaultOptions) {
409
+ return function useCreatedFormHandler(options) {
410
+ const mergedOptions = useMemo2(() => {
411
+ return {
412
+ ...defaultOptions,
413
+ ...options,
414
+ axiosConfig: {
415
+ ...defaultOptions.axiosConfig || {},
416
+ ...options.axiosConfig || {}
417
+ },
418
+ resetOptions: {
419
+ ...defaultOptions.resetOptions || {},
420
+ ...options.resetOptions || {}
421
+ }
422
+ };
423
+ }, [options]);
424
+ return useFormHandlerInternal(mergedOptions);
425
+ };
426
+ }
427
+ // src/withFormHandler.tsx
428
+ import { jsx as jsx2 } from "react/jsx-runtime";
429
+ "use client";
430
+ function withFormHandler(WrappedComponent, options) {
431
+ const WithFormHandler = (props) => {
432
+ const formHandler = useFormHandler(options);
433
+ return /* @__PURE__ */ jsx2(WrappedComponent, {
434
+ ...props,
435
+ formHandler
436
+ });
437
+ };
438
+ WithFormHandler.displayName = `WithFormHandler(${WrappedComponent.displayName || WrappedComponent.name || "Component"})`;
439
+ return WithFormHandler;
440
+ }
441
+ // src/useFormMutation.ts
442
+ import { useMutation } from "@tanstack/react-query";
443
+ import { useMemo as useMemo3, useRef as useRef2 } from "react";
444
+ "use client";
445
+ var cachedAxios2 = null;
446
+ var axiosLoadPromise2 = null;
447
+ var getAxios2 = async () => {
448
+ if (cachedAxios2)
449
+ return cachedAxios2;
450
+ if (!axiosLoadPromise2) {
451
+ axiosLoadPromise2 = import("axios").then((m) => {
452
+ cachedAxios2 = m.default || m;
453
+ return cachedAxios2;
454
+ }).catch(() => {
455
+ axiosLoadPromise2 = null;
456
+ return null;
457
+ });
458
+ }
459
+ return axiosLoadPromise2;
460
+ };
461
+ function useFormMutation(options) {
462
+ const { mutationOptions, ...formOptions } = options;
463
+ const optionsRef = useRef2(options);
464
+ optionsRef.current = options;
465
+ const form = useFormHandler(formOptions);
466
+ const mutationFn = useMemo3(() => {
467
+ return async (data) => {
468
+ const currentOpts = optionsRef.current;
469
+ if (currentOpts.service) {
470
+ return await currentOpts.service(data);
471
+ }
472
+ if (currentOpts.endpoint) {
473
+ const axiosInstance = await getAxios2();
474
+ if (!axiosInstance) {
475
+ throw new Error("axios is not installed. Please install axios or provide a custom `service` function.");
476
+ }
477
+ const res = await axiosInstance({
478
+ method: currentOpts.method || "post",
479
+ url: currentOpts.endpoint,
480
+ data,
481
+ ...currentOpts.axiosConfig
482
+ });
483
+ return res.data;
484
+ }
485
+ throw new Error("No service or endpoint provided");
486
+ };
487
+ }, []);
488
+ const mutation = useMutation({
489
+ mutationFn,
490
+ ...mutationOptions,
491
+ onSuccess: (data, variables, context) => {
492
+ optionsRef.current.onSuccess?.(data, context);
493
+ if (mutationOptions?.onSuccess) {
494
+ mutationOptions.onSuccess(data, variables, context);
495
+ }
496
+ },
497
+ onError: (error, variables, context) => {
498
+ optionsRef.current.onError?.(error, context);
499
+ if (mutationOptions?.onError) {
500
+ mutationOptions.onError(error, variables, context);
501
+ }
502
+ }
503
+ });
504
+ const reset = () => {
505
+ mutation.reset();
506
+ form.reset();
507
+ };
508
+ return {
509
+ ...form,
510
+ mutate: mutation.mutate,
511
+ mutateAsync: mutation.mutateAsync,
512
+ isPending: mutation.isPending,
513
+ isLoading: mutation.isPending,
514
+ isError: mutation.isError,
515
+ error: mutation.error,
516
+ formError: form.error,
517
+ data: mutation.data,
518
+ reset,
519
+ resetForm: form.reset,
520
+ resetMutation: mutation.reset,
521
+ status: mutation.status
522
+ };
523
+ }
524
+
525
+ // src/index.ts
526
+ "use client";
527
+ export {
528
+ FormHandlerProvider,
529
+ createFormHandler,
530
+ useFormHandler,
531
+ useFormHandlerContext,
532
+ useFormHandlerInternal,
533
+ useFormMutation,
534
+ withFormHandler
535
+ };