@gaddario98/react-core 2.0.9 → 2.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.
@@ -1,4 +1,4 @@
1
- import {jsx,Fragment,jsxs}from'react/jsx-runtime';import {useRef,useEffect,useReducer,useCallback,useMemo,useState,memo,createContext,useContext}from'react';import {atom,useAtom,useSetAtom,useAtomValue,useStore}from'jotai';import {atomWithStorage,createJSONStorage,selectAtom}from'jotai/utils';import {inflateSync,strFromU8,strToU8,deflateSync}from'fflate';import {c}from'react/compiler-runtime';import {QueryClient,useQueries,QueryObserver}from'@tanstack/react-query';import axios from'axios';import equal from'fast-deep-equal';import {atomFamily}from'jotai-family';import {useForm}from'@tanstack/react-form';/******************************************************************************
1
+ import {jsx,jsxs}from'react/jsx-runtime';import {useRef,useState,useEffect,useCallback,memo,useMemo,createContext,useContext}from'react';import {useApiValues,useApiConfigValue,useApi,queriesAtom}from'@gaddario98/react-queries';import {atom,useAtom,useStore}from'jotai';import {c}from'react/compiler-runtime';import {atomStateGenerator}from'@gaddario98/react-state';import equal from'fast-deep-equal';import {useFormValues,useFormManager}from'@gaddario98/react-form';import {atomFamily}from'jotai-family';import {QueryObserver}from'@tanstack/react-query';/******************************************************************************
2
2
  Copyright (c) Microsoft Corporation.
3
3
 
4
4
  Permission to use, copy, modify, and/or distribute this software for any
@@ -25,1593 +25,6 @@ function __rest(s, e) {
25
25
  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
26
26
  var e = new Error(message);
27
27
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
28
- };const RAW_PREFIX = 'storage:raw:';
29
- const DEFLATE_PREFIX = 'storage:deflate:v1:';
30
- const isProbablyJson = value => {
31
- if (!value) return false;
32
- const c = value.charCodeAt(0);
33
- // { [ " digits, t/f/n (true/false/null)
34
- return c === 123 || c === 91 || c === 34 || c >= 48 && c <= 57 || c === 45 || c === 116 || c === 102 || c === 110;
35
- };
36
- const u8ToBase64 = bytes => {
37
- let binary = '';
38
- const chunkSize = 0x8000;
39
- for (let i = 0; i < bytes.length; i += chunkSize) {
40
- binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
41
- }
42
- return btoa(binary);
43
- };
44
- const base64ToU8 = base64 => {
45
- const binary = atob(base64);
46
- const bytes = new Uint8Array(binary.length);
47
- for (let i = 0; i < binary.length; i++) {
48
- bytes[i] = binary.charCodeAt(i);
49
- }
50
- return bytes;
51
- };
52
- const createCompressedStorage = (base, options = {}) => {
53
- const {
54
- minSizeToCompress = 1024,
55
- deflateLevel = 1,
56
- writeDebounceMs = 50
57
- } = options;
58
- const pendingWrites = new Map();
59
- let flushTimer;
60
- let lifecycleHooksInstalled = false;
61
- const flush = () => {
62
- flushTimer = undefined;
63
- for (const [key, value] of pendingWrites) {
64
- try {
65
- if (value.length < minSizeToCompress) {
66
- base.setItem(key, RAW_PREFIX + value);
67
- continue;
68
- }
69
- const input = strToU8(value);
70
- const compressed = deflateSync(input, {
71
- level: deflateLevel
72
- });
73
- base.setItem(key, DEFLATE_PREFIX + u8ToBase64(compressed));
74
- } catch (error) {
75
- console.error('Error setting item:', error);
76
- try {
77
- base.setItem(key, RAW_PREFIX + value);
78
- } catch (_a) {
79
- // ignore
80
- }
81
- }
82
- }
83
- pendingWrites.clear();
84
- };
85
- const scheduleFlush = () => {
86
- if (flushTimer != null) return;
87
- if (!lifecycleHooksInstalled && typeof window !== 'undefined') {
88
- lifecycleHooksInstalled = true;
89
- window.addEventListener('beforeunload', flush);
90
- document.addEventListener('visibilitychange', () => {
91
- if (document.visibilityState === 'hidden') flush();
92
- });
93
- }
94
- flushTimer = globalThis.setTimeout(flush, writeDebounceMs);
95
- };
96
- return {
97
- getItem: key => {
98
- try {
99
- const stored = base.getItem(key);
100
- if (!stored) return null;
101
- if (stored.startsWith(RAW_PREFIX)) {
102
- return stored.slice(RAW_PREFIX.length);
103
- }
104
- if (stored.startsWith(DEFLATE_PREFIX)) {
105
- const b64 = stored.slice(DEFLATE_PREFIX.length);
106
- const bytes = base64ToU8(b64);
107
- const decompressed = inflateSync(bytes);
108
- return strFromU8(decompressed);
109
- }
110
- // Back-compat: older versions may have stored raw JSON without any prefix
111
- if (isProbablyJson(stored)) return stored;
112
- return null;
113
- } catch (error) {
114
- console.error('Error getting item:', error);
115
- return null;
116
- }
117
- },
118
- setItem: (key, value) => {
119
- try {
120
- // Some upstream serializers can return `undefined` (e.g. JSON.stringify(undefined)).
121
- const rawValue = value;
122
- if (rawValue == null) {
123
- pendingWrites.delete(key);
124
- base.removeItem(key);
125
- return;
126
- }
127
- const stringValue = typeof rawValue === 'string' ? rawValue : String(rawValue);
128
- pendingWrites.set(key, stringValue);
129
- scheduleFlush();
130
- } catch (error) {
131
- console.error('Error setting item:', error);
132
- }
133
- },
134
- removeItem: key => {
135
- try {
136
- pendingWrites.delete(key);
137
- base.removeItem(key);
138
- } catch (error) {
139
- console.error('Error removing item:', error);
140
- }
141
- }
142
- };
143
- };
144
- const baseStorage = {
145
- getItem: key => {
146
- if (typeof localStorage === 'undefined') return null;
147
- return localStorage.getItem(key);
148
- },
149
- setItem: (key, value) => {
150
- if (typeof localStorage === 'undefined') return;
151
- localStorage.setItem(key, value);
152
- },
153
- removeItem: key => {
154
- if (typeof localStorage === 'undefined') return;
155
- localStorage.removeItem(key);
156
- }
157
- };
158
- let storage = createCompressedStorage(baseStorage);// Implementazione
159
- function atomStateGenerator({
160
- key,
161
- defaultValue,
162
- persist = false,
163
- storage: customStorage
164
- }) {
165
- const resolvedStorage = customStorage || storage;
166
- // Usa atomWithStorage solo se persist è true, altrimenti atom normale
167
- const jotaiAtom = persist ? atomWithStorage(key, defaultValue, createJSONStorage(() => resolvedStorage)) : atom(defaultValue);
168
- const useValue = () => {
169
- const [value] = useAtom(jotaiAtom);
170
- return value;
171
- };
172
- const useState = () => {
173
- const $ = c(3);
174
- const [value, setValue] = useAtom(jotaiAtom);
175
- let t0;
176
- if ($[0] !== setValue || $[1] !== value) {
177
- t0 = [value, setValue];
178
- $[0] = setValue;
179
- $[1] = value;
180
- $[2] = t0;
181
- } else {
182
- t0 = $[2];
183
- }
184
- return t0;
185
- };
186
- const useReset = () => {
187
- const $ = c(2);
188
- const [, setValue] = useAtom(jotaiAtom);
189
- let t0;
190
- if ($[0] !== setValue) {
191
- t0 = () => {
192
- setValue(defaultValue);
193
- if (persist) {
194
- resolvedStorage.removeItem(key);
195
- }
196
- };
197
- $[0] = setValue;
198
- $[1] = t0;
199
- } else {
200
- t0 = $[1];
201
- }
202
- return t0;
203
- };
204
- return {
205
- atom: jotaiAtom,
206
- useValue,
207
- useState,
208
- useReset
209
- };
210
- }// ============================================================================
211
- // Default Values
212
- // ============================================================================
213
- const DEFAULT_QUERY_ENTRY = Object.freeze({
214
- data: undefined,
215
- isLoading: false,
216
- isLoadingMapped: false,
217
- isFetching: false,
218
- isPending: false,
219
- isSuccess: false,
220
- isError: false,
221
- isStale: false,
222
- error: null,
223
- dataUpdatedAt: 0,
224
- errorUpdatedAt: 0,
225
- fetchStatus: 'idle',
226
- refetch: () => Promise.resolve()
227
- });
228
- const DEFAULT_MUTATION_ENTRY = Object.freeze({
229
- data: undefined,
230
- status: 'idle',
231
- error: null,
232
- variables: undefined,
233
- submittedAt: 0,
234
- isIdle: true,
235
- isPending: false,
236
- isSuccess: false,
237
- isError: false,
238
- mutate: () => {},
239
- mutateAsync: async () => Promise.resolve(undefined),
240
- reset: () => {},
241
- context: 0,
242
- failureCount: 0,
243
- failureReason: null,
244
- isPaused: false
245
- });
246
- // ============================================================================
247
- // Global Atoms (single atom for all queries, single atom for all mutations)
248
- // ============================================================================
249
- /**
250
- * Global atom storing all query results.
251
- * Key format: "scopeId:queryKey"
252
- */
253
- const queriesAtom = atomWithStorage('queries-atom', {}, createJSONStorage(() => storage), {
254
- getOnInit: true
255
- });
256
- /**
257
- * Global atom storing all mutation results.
258
- * Key format: "scopeId:mutationKey"
259
- */
260
- const mutationsAtom = atom({});
261
- // ============================================================================
262
- // Helper to generate composite keys
263
- // ============================================================================
264
- const getCompositeKey = (scopeId, key) => `${scopeId}:${key}`;const apiClient = axios.create({
265
- timeout: 30000,
266
- headers: {
267
- 'Content-Type': 'application/json'
268
- }
269
- });
270
- apiClient.interceptors.response.use(response => response, error => {
271
- var _a, _b;
272
- if (error.response) {
273
- throw new Error(((_a = error.response.data) === null || _a === void 0 ? void 0 : _a.message) || ((_b = error.response.data) === null || _b === void 0 ? void 0 : _b.error) || `Error ${error.response.status}`);
274
- } else if (error.request) {
275
- throw new Error('No response from server - request timeout or network issue');
276
- } else {
277
- throw new Error('Request configuration error');
278
- }
279
- });
280
- const apiRequest = async ({
281
- method,
282
- url,
283
- body,
284
- headers,
285
- converter
286
- }) => {
287
- try {
288
- const isPrimitive = typeof body === 'string' || typeof body === 'number' || typeof body === 'boolean';
289
- let finalUrl = url;
290
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
291
- let finalBody = body;
292
- // 1. Primitive Body Handling (Append to URL)
293
- if (isPrimitive && body) {
294
- if (method !== 'POST') {
295
- finalUrl = `${url}/${body}`;
296
- finalBody = undefined;
297
- }
298
- }
299
- // 2. Object Body Handling (Path Param Replacement)
300
- if (!isPrimitive && typeof body === 'object' && body !== null) {
301
- // Look for :param in string
302
- // e.g. /users/:uid/availability
303
- const pathParams = finalUrl.match(/:[a-zA-Z0-9_]+/g);
304
- if (pathParams) {
305
- // Create shallow copy to avoid mutating original
306
- finalBody = Object.assign({}, body);
307
- pathParams.forEach(param => {
308
- if (finalBody) {
309
- const key = param.substring(1); // remove :
310
- if (key in finalBody) {
311
- finalUrl = finalUrl.replace(param, String(finalBody[key]));
312
- // Optional: remove from body if it was used in path?
313
- // Usually yes for simple IDs, maybe not for others.
314
- // Let's remove to keep body clean.
315
- delete finalBody[key];
316
- }
317
- }
318
- });
319
- }
320
- // Also handle case where we append ID to end if URL ends with / and we have 'id' or 'uid' in body?
321
- // No, explicit :param or explicit append logic is safer.
322
- // But we have logic for 'updateUser' where we just set endpoint ['api', 'users'] and method PUT.
323
- // We expect /users/123.
324
- // If body is { uid: 123, ...data }, we want /users/123.
325
- // If no :param is found, and method is PUT/DELETE/PATCH, and body has 'id' or 'uid', should we append?
326
- // User asked to eliminate customRequest.
327
- // Let's add: "If method is PUT/DELETE/PATCH, and no :param replacement happened, and body has (id|uid), append it."
328
- const hasId = 'id' in finalBody || 'uid' in finalBody;
329
- if ((method === 'PUT' || method === 'DELETE' || method === 'PATCH') && hasId && !pathParams) {
330
- const id = finalBody.id || finalBody.uid;
331
- if (id) {
332
- finalUrl = `${finalUrl}/${id}`;
333
- // We generally DON'T remove ID from body in this implicit case as it might be needed for validation
334
- // But for cleaner API calls we might want to.
335
- // Let's keep it safe: Don't remove ID here.
336
- }
337
- }
338
- }
339
- const data = converter && finalBody ? converter(finalBody) : finalBody;
340
- const response = await apiClient({
341
- url: finalUrl,
342
- method,
343
- data,
344
- headers
345
- });
346
- if (response.status >= 200 && response.status < 300) {
347
- return response.data;
348
- }
349
- throw new Error(`Request failed with status ${response.status}`);
350
- } catch (error) {
351
- console.error('API Request Error:', error);
352
- if (error instanceof Error) {
353
- throw error;
354
- }
355
- throw new Error('Unknown error occurred');
356
- }
357
- };const _endpoints = {
358
- custom: '',
359
- api: 'http://localhost:3000' // import.meta.env.VITE_API_URL ||
360
- };
361
- const defaultQueryClient = new QueryClient({
362
- defaultOptions: {
363
- queries: {
364
- retry: 2
365
- // staleTime: 2 * 60 * 1000,
366
- }
367
- }
368
- });
369
- const {
370
- useValue: useApiConfigValue} = atomStateGenerator({
371
- key: 'apiConfig',
372
- defaultValue: {
373
- endpoints: _endpoints,
374
- requestFn: apiRequest,
375
- queryClient: defaultQueryClient
376
- },
377
- persist: false
378
- });const useMultipleQuery = t0 => {
379
- const $ = c(30);
380
- let t1;
381
- if ($[0] !== t0) {
382
- t1 = t0 === undefined ? [] : t0;
383
- $[0] = t0;
384
- $[1] = t1;
385
- } else {
386
- t1 = $[1];
387
- }
388
- const settings = t1;
389
- const {
390
- requestFn,
391
- validateAuthFn,
392
- defaultHeaders,
393
- queryClient,
394
- endpoints
395
- } = useApiConfigValue();
396
- let t2;
397
- if ($[2] !== endpoints) {
398
- t2 = endpoint => {
399
- const [key, path] = endpoint;
400
- const baseUrl = endpoints[key];
401
- return [baseUrl, path].filter(Boolean).join("/");
402
- };
403
- $[2] = endpoints;
404
- $[3] = t2;
405
- } else {
406
- t2 = $[3];
407
- }
408
- const generateEndpoint = t2;
409
- let t3;
410
- if ($[4] !== validateAuthFn) {
411
- t3 = validateAuthFn ? validateAuthFn() : true;
412
- $[4] = validateAuthFn;
413
- $[5] = t3;
414
- } else {
415
- t3 = $[5];
416
- }
417
- const isLogged = t3;
418
- let t4;
419
- if ($[6] !== defaultHeaders || $[7] !== generateEndpoint || $[8] !== requestFn) {
420
- t4 = async t5 => {
421
- const {
422
- endpoint: endpoint_0,
423
- customQueryFn,
424
- headers
425
- } = t5;
426
- const fullEndpoint = generateEndpoint(endpoint_0);
427
- if (customQueryFn) {
428
- const res = await customQueryFn();
429
- return res;
430
- }
431
- const mergedHeaders = Object.assign(Object.assign({}, defaultHeaders), headers);
432
- return await requestFn({
433
- url: fullEndpoint,
434
- method: "GET",
435
- headers: mergedHeaders
436
- });
437
- };
438
- $[6] = defaultHeaders;
439
- $[7] = generateEndpoint;
440
- $[8] = requestFn;
441
- $[9] = t4;
442
- } else {
443
- t4 = $[9];
444
- }
445
- const generateQueryFn = t4;
446
- let t5;
447
- let t6;
448
- if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
449
- t5 = {};
450
- t6 = {};
451
- $[10] = t5;
452
- $[11] = t6;
453
- } else {
454
- t5 = $[10];
455
- t6 = $[11];
456
- }
457
- let t7;
458
- if ($[12] !== settings) {
459
- t7 = {
460
- settings,
461
- data: t5,
462
- results: t6
463
- };
464
- $[12] = settings;
465
- $[13] = t7;
466
- } else {
467
- t7 = $[13];
468
- }
469
- const ref = useRef(t7);
470
- let t8;
471
- let t9;
472
- if ($[14] !== settings) {
473
- t8 = () => {
474
- ref.current.settings = settings;
475
- };
476
- t9 = [settings];
477
- $[14] = settings;
478
- $[15] = t8;
479
- $[16] = t9;
480
- } else {
481
- t8 = $[15];
482
- t9 = $[16];
483
- }
484
- useEffect(t8, t9);
485
- let t10;
486
- if ($[17] !== generateQueryFn || $[18] !== isLogged || $[19] !== settings) {
487
- let t11;
488
- if ($[21] !== generateQueryFn || $[22] !== isLogged) {
489
- t11 = setting => {
490
- const {
491
- queryKey,
492
- enabled: t12,
493
- disableAuthControl
494
- } = setting;
495
- const enabled = t12 === undefined ? true : t12;
496
- const rest = __rest(setting, ["queryKey", "enabled", "disableAuthControl"]);
497
- return Object.assign({
498
- queryKey,
499
- queryFn: () => generateQueryFn(setting),
500
- enabled: !!enabled && (disableAuthControl || !!isLogged)
501
- }, rest);
502
- };
503
- $[21] = generateQueryFn;
504
- $[22] = isLogged;
505
- $[23] = t11;
506
- } else {
507
- t11 = $[23];
508
- }
509
- t10 = settings.map(t11);
510
- $[17] = generateQueryFn;
511
- $[18] = isLogged;
512
- $[19] = settings;
513
- $[20] = t10;
514
- } else {
515
- t10 = $[20];
516
- }
517
- const queries = t10;
518
- let t11;
519
- if ($[24] === Symbol.for("react.memo_cache_sentinel")) {
520
- t11 = results => results.reduce((prev, result, index) => {
521
- const setting_0 = ref.current.settings[index];
522
- const keyToMap = setting_0.keyToMap;
523
- Object.assign(prev, {
524
- [keyToMap]: {
525
- data: result.data,
526
- isLoadingMapped: !setting_0.disableLoading && result.isLoading,
527
- isLoading: result.isLoading,
528
- isFetching: result.isFetching,
529
- isPending: result.isPending,
530
- error: result.error,
531
- refetch: result.refetch
532
- }
533
- });
534
- return prev;
535
- }, {});
536
- $[24] = t11;
537
- } else {
538
- t11 = $[24];
539
- }
540
- const combine = t11;
541
- let t12;
542
- if ($[25] !== queries) {
543
- t12 = {
544
- queries,
545
- combine
546
- };
547
- $[25] = queries;
548
- $[26] = t12;
549
- } else {
550
- t12 = $[26];
551
- }
552
- const result_0 = useQueries(t12, queryClient);
553
- let t13;
554
- let t14;
555
- if ($[27] !== result_0) {
556
- t13 = () => {
557
- ref.current.settings.forEach(setting_1 => {
558
- const {
559
- keyToMap: keyToMap_0,
560
- onDataChanged,
561
- onStateChange
562
- } = setting_1;
563
- if (!onDataChanged && !onStateChange) {
564
- return;
565
- }
566
- const currentResult = result_0[keyToMap_0];
567
- const prevResult = ref.current.results[keyToMap_0];
568
- if (onStateChange) {
569
- if (!prevResult || prevResult.data !== currentResult.data || prevResult.isLoading !== currentResult.isLoading || prevResult.isLoadingMapped !== currentResult.isLoadingMapped || prevResult.isFetching !== currentResult.isFetching || prevResult.isPending !== currentResult.isPending || prevResult.error !== currentResult.error) {
570
- ref.current.results[keyToMap_0] = currentResult;
571
- onStateChange(currentResult);
572
- }
573
- }
574
- if (onDataChanged) {
575
- const currentData = currentResult.data;
576
- const prevData = ref.current.data[keyToMap_0];
577
- if (currentData !== undefined && currentData !== prevData) {
578
- ref.current.data[keyToMap_0] = currentData;
579
- onDataChanged(currentData);
580
- }
581
- }
582
- });
583
- };
584
- t14 = [result_0];
585
- $[27] = result_0;
586
- $[28] = t13;
587
- $[29] = t14;
588
- } else {
589
- t13 = $[28];
590
- t14 = $[29];
591
- }
592
- useEffect(t13, t14);
593
- return result_0;
594
- };/* eslint-disable @typescript-eslint/no-explicit-any */
595
- const defaultState = DEFAULT_MUTATION_ENTRY;
596
- const mutationReducer = (state, action) => {
597
- switch (action.type) {
598
- case "RESET":
599
- return Object.assign(Object.assign({}, state), {
600
- [action.key]: Object.assign({}, defaultState)
601
- });
602
- case "PENDING":
603
- return Object.assign(Object.assign({}, state), {
604
- [action.key]: {
605
- status: "pending",
606
- data: undefined,
607
- error: null,
608
- submittedAt: action.submittedAt,
609
- variables: action.variables
610
- }
611
- });
612
- case "SUCCESS":
613
- return Object.assign(Object.assign({}, state), {
614
- [action.key]: Object.assign(Object.assign({}, state[action.key]), {
615
- status: "success",
616
- data: action.data,
617
- error: null
618
- })
619
- });
620
- case "ERROR":
621
- return Object.assign(Object.assign({}, state), {
622
- [action.key]: Object.assign(Object.assign({}, state[action.key]), {
623
- status: "error",
624
- error: action.error
625
- })
626
- });
627
- default:
628
- return state;
629
- }
630
- };
631
- const initMutationStates = configs => {
632
- const states = {};
633
- configs.forEach(config => {
634
- states[config.key] = Object.assign({}, defaultState);
635
- });
636
- return states;
637
- };
638
- const useMultipleMutation = configs => {
639
- const {
640
- requestFn,
641
- validateAuthFn,
642
- defaultHeaders,
643
- queryClient,
644
- showNotification,
645
- endpoints
646
- } = useApiConfigValue();
647
- const [reducerStates, dispatchReducer] = useReducer(mutationReducer, configs, initMutationStates);
648
- // Accessor for current state
649
- const getState = useCallback(key => {
650
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
651
- return reducerStates[key] || defaultState;
652
- }, [reducerStates]);
653
- // Dispatcher that handles both modes
654
- const dispatch = useCallback(action => {
655
- dispatchReducer(action);
656
- }, []);
657
- const executeMutation = useCallback(async (key_0, config, data, mutationOptions) => {
658
- var _a, _b, _c, _d, _e, _f, _g;
659
- const {
660
- endpoint,
661
- method,
662
- headers,
663
- queryKeyToInvalidate,
664
- customRequest,
665
- converter,
666
- isTest,
667
- notification,
668
- mutateOptions
669
- } = config;
670
- dispatch({
671
- type: "PENDING",
672
- key: key_0,
673
- submittedAt: Date.now(),
674
- variables: data
675
- });
676
- let context;
677
- try {
678
- // Auth validation
679
- const isValidAuth = validateAuthFn ? validateAuthFn() : true;
680
- if (!isValidAuth) {
681
- throw new Error("Utente non autenticato");
682
- }
683
- // Build endpoint
684
- const [endpointKey, path] = endpoint;
685
- const baseUrl = (_a = endpoints[endpointKey]) !== null && _a !== void 0 ? _a : "";
686
- const fullEndpoint = [baseUrl, path].filter(Boolean).join("/");
687
- // Merge headers
688
- const mergedHeaders = Object.assign(Object.assign({}, defaultHeaders), headers);
689
- // Execute request
690
- let result;
691
- if (isTest) {
692
- result = "test";
693
- } else if (customRequest) {
694
- result = await customRequest(fullEndpoint, method, data);
695
- } else {
696
- result = await requestFn({
697
- url: fullEndpoint,
698
- method,
699
- body: data,
700
- headers: mergedHeaders,
701
- converter
702
- });
703
- }
704
- dispatch({
705
- type: "SUCCESS",
706
- key: key_0,
707
- data: result
708
- });
709
- // Invalidate queries
710
- if (queryKeyToInvalidate) {
711
- queryKeyToInvalidate.forEach(qKey => {
712
- queryClient.invalidateQueries({
713
- queryKey: [qKey],
714
- exact: false
715
- });
716
- });
717
- }
718
- // Success notification
719
- const notificationProps_0 = typeof (notification === null || notification === void 0 ? void 0 : notification.success) === "function" ? notification.success(result) : notification === null || notification === void 0 ? void 0 : notification.success;
720
- if (notificationProps_0 === null || notificationProps_0 === void 0 ? void 0 : notificationProps_0.message) {
721
- showNotification === null || showNotification === void 0 ? void 0 : showNotification(Object.assign({
722
- message: notificationProps_0.message,
723
- type: (_b = notificationProps_0.type) !== null && _b !== void 0 ? _b : "success"
724
- }, notificationProps_0));
725
- }
726
- // Callbacks
727
- // @ts-expect-error - MutateOptions callback signature varies by TanStack Query version
728
- (_c = mutateOptions === null || mutateOptions === void 0 ? void 0 : mutateOptions.onSuccess) === null || _c === void 0 ? void 0 : _c.call(mutateOptions, result, data, context);
729
- (_d = mutationOptions === null || mutationOptions === void 0 ? void 0 : mutationOptions.onSuccess) === null || _d === void 0 ? void 0 : _d.call(mutationOptions, result, data, undefined, context);
730
- return result;
731
- } catch (error) {
732
- const err = error instanceof Error ? error : new Error("Unknown error");
733
- dispatch({
734
- type: "ERROR",
735
- key: key_0,
736
- error: err
737
- });
738
- // Error notification
739
- const notificationProps = typeof (notification === null || notification === void 0 ? void 0 : notification.error) === "function" ? notification.error(err.message) : notification === null || notification === void 0 ? void 0 : notification.error;
740
- if ((notificationProps === null || notificationProps === void 0 ? void 0 : notificationProps.message) || err.message) {
741
- showNotification === null || showNotification === void 0 ? void 0 : showNotification(Object.assign({
742
- message: (notificationProps === null || notificationProps === void 0 ? void 0 : notificationProps.message) || err.message || "An unexpected error occurred",
743
- type: (_e = notificationProps === null || notificationProps === void 0 ? void 0 : notificationProps.type) !== null && _e !== void 0 ? _e : "error"
744
- }, notificationProps));
745
- }
746
- // Callbacks
747
- // @ts-expect-error - MutateOptions callback signature varies by TanStack Query version
748
- (_f = mutateOptions === null || mutateOptions === void 0 ? void 0 : mutateOptions.onError) === null || _f === void 0 ? void 0 : _f.call(mutateOptions, err, data, context);
749
- (_g = mutationOptions === null || mutationOptions === void 0 ? void 0 : mutationOptions.onError) === null || _g === void 0 ? void 0 : _g.call(mutationOptions, err, data, undefined, context);
750
- throw err;
751
- }
752
- }, [queryClient, validateAuthFn, defaultHeaders, endpoints, requestFn, showNotification, dispatch // dispatch is now stable/wrapped
753
- ]);
754
- const ref = useRef({
755
- dispatch,
756
- executeMutation
757
- });
758
- useEffect(() => {
759
- ref.current = {
760
- dispatch,
761
- executeMutation
762
- };
763
- }, [dispatch, executeMutation]);
764
- const allMutation = useMemo(() => {
765
- const result_0 = {};
766
- configs.forEach(item => {
767
- var _a_0, _b_0, _c_0;
768
- // In silent mode, this is just the INITIAL state (or whatever triggered last render).
769
- // The real data comes from Proxy if used.
770
- const state = getState(item.key);
771
- const mutationConfig = item.mutationConfig;
772
- const mutationKey = item.key;
773
- result_0[mutationKey] = {
774
- // State
775
- data: state.data,
776
- error: state.error,
777
- isIdle: state.status === "idle",
778
- isPending: state.status === "pending",
779
- isSuccess: state.status === "success",
780
- isError: state.status === "error",
781
- status: state.status,
782
- variables: state.variables,
783
- submittedAt: (_a_0 = state.submittedAt) !== null && _a_0 !== void 0 ? _a_0 : 0,
784
- endpoint: mutationConfig.endpoint,
785
- // Methods
786
- mutate: (data_0, mutationOptions_0) => {
787
- ref.current.executeMutation(item.key, mutationConfig, data_0, mutationOptions_0);
788
- },
789
- mutateAsync: (data_1, mutationOptions_1) => {
790
- return ref.current.executeMutation(item.key, mutationConfig, data_1, mutationOptions_1);
791
- },
792
- reset: () => ref.current.dispatch({
793
- type: "RESET",
794
- key: item.key
795
- }),
796
- // Compatibility fields
797
- failureCount: 0,
798
- failureReason: null,
799
- context: undefined,
800
- isPaused: false
801
- };
802
- (_c_0 = (_b_0 = item.mutationConfig).onStateChange) === null || _c_0 === void 0 ? void 0 : _c_0.call(_b_0, result_0[mutationKey]);
803
- });
804
- return result_0;
805
- }, [getState, configs]);
806
- return allMutation;
807
- };const useMultipleWebSocket = (configs = []) => {
808
- const {
809
- websocketConfig
810
- } = useApiConfigValue();
811
- const {
812
- queryClient
813
- } = useApiConfigValue();
814
- const socketsRef = useRef(new Map());
815
- const [statuses, setStatuses] = useState(new Map());
816
- const [lastMessages, setLastMessages] = useState(new Map());
817
- // Stabilize configs reference
818
- const stableConfigs = useMemo(() => configs, [configs]);
819
- useEffect(() => {
820
- const sockets = socketsRef.current;
821
- stableConfigs.forEach(config => {
822
- const url = config.endpoint || (websocketConfig === null || websocketConfig === void 0 ? void 0 : websocketConfig.url);
823
- const shouldConnect = config.autoConnect !== false && ((websocketConfig === null || websocketConfig === void 0 ? void 0 : websocketConfig.autoConnect) || config.endpoint);
824
- if (!url || !shouldConnect) return;
825
- // Skip if already connected
826
- if (sockets.has(config.key)) return;
827
- setStatuses(prev => new Map(prev).set(config.key, 'connecting'));
828
- const ws = new WebSocket(url);
829
- sockets.set(config.key, ws);
830
- ws.onopen = () => {
831
- setStatuses(prev_0 => new Map(prev_0).set(config.key, 'open'));
832
- console.log(`WebSocket [${config.key}] connected`);
833
- };
834
- ws.onmessage = event => {
835
- var _a, _b;
836
- try {
837
- const data = JSON.parse(event.data);
838
- setLastMessages(prev_1 => new Map(prev_1).set(config.key, data));
839
- // Global handler
840
- (_a = websocketConfig === null || websocketConfig === void 0 ? void 0 : websocketConfig.onMessage) === null || _a === void 0 ? void 0 : _a.call(websocketConfig, data);
841
- // Local handler
842
- (_b = config.onMessage) === null || _b === void 0 ? void 0 : _b.call(config, data);
843
- // Auto invalidation
844
- if (config.invalidateQueriesOnMessage && Array.isArray(config.invalidateQueriesOnMessage)) {
845
- config.invalidateQueriesOnMessage.forEach(key => {
846
- queryClient.invalidateQueries({
847
- queryKey: [key],
848
- exact: false
849
- });
850
- });
851
- }
852
- } catch (e) {
853
- console.error(`WebSocket [${config.key}] message parse error`, e);
854
- }
855
- };
856
- ws.onclose = () => {
857
- setStatuses(prev_2 => new Map(prev_2).set(config.key, 'closed'));
858
- console.log(`WebSocket [${config.key}] disconnected`);
859
- sockets.delete(config.key);
860
- };
861
- });
862
- return () => {
863
- sockets.forEach((ws_0, key_0) => {
864
- ws_0.close();
865
- sockets.delete(key_0);
866
- });
867
- };
868
- }, [stableConfigs, websocketConfig, queryClient]);
869
- const createSendMessage = useCallback(key_1 => message => {
870
- const ws_1 = socketsRef.current.get(key_1);
871
- if ((ws_1 === null || ws_1 === void 0 ? void 0 : ws_1.readyState) === WebSocket.OPEN) {
872
- ws_1.send(JSON.stringify(message));
873
- } else {
874
- console.warn(`WebSocket [${key_1}] is not open`);
875
- }
876
- }, []);
877
- const result = useMemo(() => {
878
- const mapped = {};
879
- stableConfigs.forEach(config_0 => {
880
- var _a_0, _b_0;
881
- mapped[config_0.key] = {
882
- lastMessage: (_a_0 = lastMessages.get(config_0.key)) !== null && _a_0 !== void 0 ? _a_0 : null,
883
- sendMessage: createSendMessage(config_0.key),
884
- status: (_b_0 = statuses.get(config_0.key)) !== null && _b_0 !== void 0 ? _b_0 : 'closed'
885
- };
886
- });
887
- return mapped;
888
- }, [stableConfigs, lastMessages, statuses, createSendMessage]);
889
- return result;
890
- };function useApi(configs, optionsOrId) {
891
- const options = typeof optionsOrId === 'string' ? {
892
- scopeId: optionsOrId
893
- } : optionsOrId !== null && optionsOrId !== void 0 ? optionsOrId : {};
894
- const {
895
- scopeId = 'default',
896
- persistToAtoms = true
897
- } = options;
898
- // Global atom setters
899
- const setQueriesAtom = useSetAtom(queriesAtom);
900
- const setMutationsAtom = useSetAtom(mutationsAtom);
901
- // Update a single query in the global atom
902
- const updateQueryAtom = useCallback((key, state) => {
903
- const compositeKey = getCompositeKey(scopeId, key);
904
- setQueriesAtom(prev => Object.assign(Object.assign({}, prev), {
905
- [compositeKey]: state
906
- }));
907
- }, [setQueriesAtom, scopeId]);
908
- // Update a single mutation in the global atom
909
- const updateMutationAtom = useCallback((key, state) => {
910
- const compositeKey = getCompositeKey(scopeId, key);
911
- setMutationsAtom(prev => Object.assign(Object.assign({}, prev), {
912
- [compositeKey]: state
913
- }));
914
- }, [setMutationsAtom, scopeId]);
915
- // Enhanced query configs with atom persistence
916
- const enhancedQueryConfigs = useMemo(() => {
917
- const items = configs.filter(q => q.type === 'query');
918
- return items.map(item => {
919
- if (!item.queryConfig) return null;
920
- const key = item.key;
921
- const originalOnStateChange = item.queryConfig.onStateChange;
922
- return Object.assign(Object.assign({}, item.queryConfig), {
923
- keyToMap: key,
924
- onStateChange: state => {
925
- if (persistToAtoms) {
926
- updateQueryAtom(key, state);
927
- }
928
- originalOnStateChange === null || originalOnStateChange === void 0 ? void 0 : originalOnStateChange(state);
929
- },
930
- options: item.queryConfig.options
931
- });
932
- }).filter(Boolean);
933
- // eslint-disable-next-line react-hooks/exhaustive-deps
934
- }, [
935
- // eslint-disable-next-line react-hooks/exhaustive-deps
936
- JSON.stringify(configs), persistToAtoms, updateQueryAtom]);
937
- // Enhanced mutation configs with atom persistence
938
- const enhancedMutationItems = useMemo(() => {
939
- const items = configs.filter(q => q.type === 'mutation' && !!q.mutationConfig);
940
- return items.map(item => {
941
- const key = item.key;
942
- const originalOnStateChange = item.mutationConfig.onStateChange;
943
- return Object.assign(Object.assign({}, item), {
944
- mutationConfig: Object.assign(Object.assign({}, item.mutationConfig), {
945
- onStateChange: state => {
946
- if (persistToAtoms) {
947
- updateMutationAtom(key, state);
948
- }
949
- originalOnStateChange === null || originalOnStateChange === void 0 ? void 0 : originalOnStateChange(state);
950
- }
951
- })
952
- });
953
- });
954
- // eslint-disable-next-line react-hooks/exhaustive-deps
955
- }, [JSON.stringify(configs), persistToAtoms, updateMutationAtom]);
956
- const webSocketItems = useMemo(() => configs.filter(q => q.type === 'websocket'),
957
- // eslint-disable-next-line react-hooks/exhaustive-deps
958
- [JSON.stringify(configs)]);
959
- // Execute hooks
960
- const allQuery = useMultipleQuery(enhancedQueryConfigs);
961
- const allMutation = useMultipleMutation(enhancedMutationItems);
962
- const allWebSocket = useMultipleWebSocket(webSocketItems);
963
- const queryKeys = enhancedQueryConfigs.map(el => el.keyToMap);
964
- const mutationKeys = enhancedMutationItems.map(el => el.key);
965
- const ref = useRef({
966
- allQuery,
967
- allMutation,
968
- queryKeys,
969
- mutationKeys
970
- });
971
- useEffect(() => {
972
- ref.current = {
973
- allQuery,
974
- allMutation,
975
- queryKeys,
976
- mutationKeys
977
- };
978
- }, [allQuery, allMutation, queryKeys, mutationKeys]);
979
- const refreshQueries = useCallback(() => {
980
- ref.current.queryKeys.forEach(k => {
981
- ref.current.allQuery[k].refetch();
982
- });
983
- }, []);
984
- return {
985
- allQuery,
986
- allMutation,
987
- allWebSocket,
988
- refreshQueries
989
- };
990
- }// ============================================================================
991
- // Bulk Query/Mutation Hooks
992
- // ============================================================================
993
- /**
994
- * Hook to read all queries for a scope.
995
- */
996
- function useJotaiQueries(options) {
997
- const $ = c(3);
998
- const {
999
- scopeId
1000
- } = options;
1001
- const allQueries = useAtomValue(queriesAtom);
1002
- const prefix = `${scopeId}:`;
1003
- let scopeQueries;
1004
- if ($[0] !== allQueries || $[1] !== prefix) {
1005
- scopeQueries = {};
1006
- for (const [key, value] of Object.entries(allQueries)) {
1007
- if (key.startsWith(prefix)) {
1008
- scopeQueries[key.slice(prefix.length)] = value;
1009
- }
1010
- }
1011
- $[0] = allQueries;
1012
- $[1] = prefix;
1013
- $[2] = scopeQueries;
1014
- } else {
1015
- scopeQueries = $[2];
1016
- }
1017
- return scopeQueries;
1018
- }
1019
- /**
1020
- * Hook to read all mutations for a scope.
1021
- */
1022
- function useJotaiMutations(options) {
1023
- const $ = c(3);
1024
- const {
1025
- scopeId
1026
- } = options;
1027
- const allMutations = useAtomValue(mutationsAtom);
1028
- const prefix = `${scopeId}:`;
1029
- let scopeMutations;
1030
- if ($[0] !== allMutations || $[1] !== prefix) {
1031
- scopeMutations = {};
1032
- for (const [key, value] of Object.entries(allMutations)) {
1033
- if (key.startsWith(prefix)) {
1034
- scopeMutations[key.slice(prefix.length)] = value;
1035
- }
1036
- }
1037
- $[0] = allMutations;
1038
- $[1] = prefix;
1039
- $[2] = scopeMutations;
1040
- } else {
1041
- scopeMutations = $[2];
1042
- }
1043
- return scopeMutations;
1044
- }const getValueAtPath$2 = (obj, path, defaultObj) => {
1045
- if (!path) return undefined;
1046
- const normalized = path.replace(/\[(\d+)\]/g, ".$1");
1047
- const parts = normalized.split(".").filter(Boolean);
1048
- let current = obj;
1049
- for (let index = 0; index < parts.length; index++) {
1050
- const part = parts[index];
1051
- if (current == null) return undefined;
1052
- if (typeof current !== "object") return undefined;
1053
- const record = current;
1054
- // Only apply the default entry when the *root* key is missing (e.g. queryKey not found).
1055
- // For deeper missing paths, return undefined so callers can use the provided defaultValue.
1056
- if (!(part in record)) {
1057
- if (index === 0 && defaultObj !== undefined) {
1058
- current = defaultObj;
1059
- continue;
1060
- }
1061
- return undefined;
1062
- }
1063
- current = record[part];
1064
- }
1065
- return current;
1066
- };
1067
- const useApiValues = ({
1068
- scopeId
1069
- }) => {
1070
- const allQuery = useJotaiQueries({
1071
- scopeId
1072
- });
1073
- const allMutation = useJotaiMutations({
1074
- scopeId
1075
- });
1076
- const subscriptions = useRef(new Map());
1077
- const [trigger, setTrigger] = useState(0);
1078
- const dataRef = useRef({
1079
- query: allQuery,
1080
- mutation: allMutation
1081
- });
1082
- // Sync dataRef with latest values
1083
- useEffect(() => {
1084
- let internalTrigger = false;
1085
- const currentQuery = dataRef.current.query;
1086
- subscriptions.current.forEach((_, key) => {
1087
- const [type, keyPath] = key.split(":");
1088
- if (type === "query") {
1089
- const newValue = getValueAtPath$2(allQuery, keyPath);
1090
- const oldValue = getValueAtPath$2(currentQuery, keyPath);
1091
- // console.log(key, !equal(newValue, oldValue), newValue, oldValue)
1092
- if (!equal(newValue, oldValue)) {
1093
- internalTrigger = true;
1094
- }
1095
- }
1096
- if (type === "mutation") {
1097
- const newValue = getValueAtPath$2(allMutation, keyPath);
1098
- const oldValue = getValueAtPath$2(dataRef.current.mutation, keyPath);
1099
- if (!equal(newValue, oldValue)) {
1100
- internalTrigger = true;
1101
- }
1102
- }
1103
- });
1104
- dataRef.current = {
1105
- query: allQuery,
1106
- mutation: allMutation
1107
- };
1108
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1109
- if (internalTrigger) {
1110
- setTrigger(v => v + 1);
1111
- }
1112
- }, [allQuery, allMutation]);
1113
- // get che legge dallo store e registra le dipendenze
1114
- const get = useCallback((type, key, defaultValue) => {
1115
- var _a;
1116
- const keyMap = `${type}:${key}`;
1117
- const defaultQueries = type === "query" ? DEFAULT_QUERY_ENTRY :
1118
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1119
- type === "mutation" ? DEFAULT_MUTATION_ENTRY : undefined;
1120
- const value = (_a = getValueAtPath$2(dataRef.current[type], String(key), defaultQueries)) !== null && _a !== void 0 ? _a : defaultValue;
1121
- subscriptions.current.set(keyMap, value);
1122
- return subscriptions.current.get(keyMap);
1123
- },
1124
- // eslint-disable-next-line react-hooks/exhaustive-deps
1125
- [trigger]);
1126
- return {
1127
- get
1128
- };
1129
- };new TextEncoder();
1130
- new TextDecoder();const DefaultContainer$1 = ({
1131
- children
1132
- }) => {
1133
- return children;
1134
- };
1135
- // Lazy initialization to avoid side effects at module load time
1136
- const _formConfig = {
1137
- formFieldContainer: DefaultContainer$1
1138
- };
1139
- const {
1140
- useValue: useFormConfigValue} = atomStateGenerator({
1141
- key: 'formConfig',
1142
- defaultValue: _formConfig,
1143
- persist: false
1144
- });/* eslint-disable @typescript-eslint/no-explicit-any */
1145
- function useJotaiForm(formOptions) {
1146
- const form = useForm(formOptions);
1147
- return form;
1148
- }const FormField = ({
1149
- config,
1150
- onFieldChange,
1151
- ns: globalNs,
1152
- globalErrorNs
1153
- }) => {
1154
- var _a, _b;
1155
- const ns = (_a = config.ns) !== null && _a !== void 0 ? _a : globalNs;
1156
- const errorNs = (_b = config.errorNs) !== null && _b !== void 0 ? _b : globalErrorNs;
1157
- const {
1158
- formFieldContainer,
1159
- translateText
1160
- } = useFormConfigValue();
1161
- // TanStack Form uses field.state.meta.errors which is an array of ValidationError
1162
- const firstError = config.field.state.meta.errors.length > 0 ? config.field.state.meta.errors[0] : undefined;
1163
- const errorMessageStr = firstError ? String(firstError) : undefined;
1164
- const errorMessage = useMemo(() => {
1165
- if (!errorMessageStr) return undefined;
1166
- return errorNs ? translateText === null || translateText === void 0 ? void 0 : translateText(errorMessageStr, {
1167
- ns: errorNs || '',
1168
- defaultValue: ''
1169
- }) : errorMessageStr;
1170
- }, [errorMessageStr, errorNs, translateText]);
1171
- const label = useMemo(() => {
1172
- var _a_0;
1173
- return ns ? translateText === null || translateText === void 0 ? void 0 : translateText((_a_0 = config.label) !== null && _a_0 !== void 0 ? _a_0 : '') : config.label;
1174
- }, [ns, config.label, translateText]);
1175
- const helperMessage = useMemo(() => {
1176
- var _a_1;
1177
- return ((_a_1 = config.helper) === null || _a_1 === void 0 ? void 0 : _a_1.text) ? translateText === null || translateText === void 0 ? void 0 : translateText(config.helper.text, config.helper.translationOption) : '';
1178
- }, [config.helper, translateText]);
1179
- const ref = useRef({
1180
- onFieldChange,
1181
- handleChange: config.field.handleChange
1182
- });
1183
- useEffect(() => {
1184
- ref.current = {
1185
- onFieldChange,
1186
- handleChange: config.field.handleChange
1187
- };
1188
- }, [config.field.handleChange, onFieldChange]);
1189
- const handleChange = useCallback(value => {
1190
- var _a_2, _b_0;
1191
- // TanStack Form handleChange usually expects just the value for input
1192
- // but if we are manually calling it we should pass the value.
1193
- ref.current.handleChange(value);
1194
- (_b_0 = (_a_2 = ref.current).onFieldChange) === null || _b_0 === void 0 ? void 0 : _b_0.call(_a_2, value);
1195
- }, []);
1196
- const handleBlur = useCallback(() => {
1197
- config.field.handleBlur();
1198
- }, [config.field]);
1199
- const baseProps = useMemo(() => ({
1200
- value: config.field.state.value,
1201
- onChange: handleChange,
1202
- onBlur: handleBlur,
1203
- error: config.field.state.meta.errors.length > 0,
1204
- errorMessage,
1205
- label,
1206
- helperMessage
1207
- }), [config.field.state.value, handleChange, handleBlur, config.field.state.meta.errors.length, errorMessage, label, helperMessage]);
1208
- const ConfigContainer = useMemo(() => config.container, [config.container]);
1209
- const FormFieldContainer = useMemo(() => formFieldContainer, [formFieldContainer]);
1210
- if (ConfigContainer) {
1211
- return jsx(ConfigContainer, {
1212
- children: config.component(baseProps)
1213
- });
1214
- }
1215
- return jsx(FormFieldContainer, {
1216
- children: config.component(baseProps)
1217
- });
1218
- };const DEFAULT_FORM_ENTRY = Object.freeze({
1219
- formValues: {},
1220
- setValue: () => {}
1221
- });
1222
- /**
1223
- * Global atom storing all form state.
1224
- * Key format: "scopeId:formId" or just "formId" for backward compatibility.
1225
- */
1226
- const formAtom = atom({});
1227
- const createFormSelector = formId => selectAtom(formAtom, forms => {
1228
- const entry = forms[formId];
1229
- return entry !== null && entry !== void 0 ? entry : DEFAULT_FORM_ENTRY;
1230
- }, (a, b) => a === b || a.formValues === b.formValues && a.setValue === b.setValue);
1231
- const useFormValue = formId => {
1232
- const $ = c(2);
1233
- let t0;
1234
- if ($[0] !== formId) {
1235
- t0 = createFormSelector(formId);
1236
- $[0] = formId;
1237
- $[1] = t0;
1238
- } else {
1239
- t0 = $[1];
1240
- }
1241
- const selectorAtom = t0;
1242
- return useAtomValue(selectorAtom);
1243
- };
1244
- const useSetFormState = formId => {
1245
- const setForms = useSetAtom(formAtom);
1246
- return useCallback(val => {
1247
- setForms(prev => {
1248
- var _a;
1249
- const prevEntry = (_a = prev[formId]) !== null && _a !== void 0 ? _a : DEFAULT_FORM_ENTRY;
1250
- return Object.assign(Object.assign({}, prev), {
1251
- [formId]: Object.assign(Object.assign({}, prevEntry), val)
1252
- });
1253
- });
1254
- }, [formId, setForms]);
1255
- };const getValueAtPath$1 = (obj, path, defaultObj) => {
1256
- if (!path) return undefined;
1257
- const normalized = path.replace(/\[(\d+)\]/g, '.$1');
1258
- const parts = normalized.split('.').filter(Boolean);
1259
- let current = obj;
1260
- for (const part of parts) {
1261
- if (!current || !Object.keys(current).length) {
1262
- return undefined;
1263
- }
1264
- if (typeof current !== 'object') return undefined;
1265
- current = current[part];
1266
- }
1267
- return current;
1268
- };
1269
- const useFormValues = ({
1270
- formId
1271
- }) => {
1272
- // We subscribe to the specific form entry in the atoms
1273
- // Note: This subscription is a bit coarse (entire form entry), but we optimize re-renders locally
1274
- // Ideally we would want to subscribe only to specific paths, but Jotai atoms are per-form.
1275
- const formEntry = useFormValue(formId);
1276
- const currentValues = useMemo(() => formEntry.formValues, [formEntry.formValues]);
1277
- const subscriptions = useRef(new Map());
1278
- // trigger state is used to force re-render when a subscribed value changes
1279
- const [trigger, setTrigger] = useState(0);
1280
- // Ref to hold the latest values without causing re-renders itself
1281
- const formRef = useRef({
1282
- formValues: formEntry.formValues,
1283
- setValue: formEntry.setValue
1284
- });
1285
- useEffect(() => {
1286
- formRef.current.setValue = formEntry.setValue;
1287
- }, [formEntry.setValue]);
1288
- useEffect(() => {
1289
- let shouldTrigger = false;
1290
- subscriptions.current.forEach((_, path) => {
1291
- const newValue = getValueAtPath$1(currentValues, path);
1292
- const oldValue = getValueAtPath$1(formRef.current.formValues, path);
1293
- if (!equal(newValue, oldValue)) {
1294
- shouldTrigger = true;
1295
- }
1296
- });
1297
- formRef.current.formValues = currentValues;
1298
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1299
- if (shouldTrigger) {
1300
- setTrigger(c => c + 1);
1301
- }
1302
- }, [currentValues]);
1303
- const get = useCallback((key, defaultValue) => {
1304
- var _a;
1305
- const val = (_a = getValueAtPath$1(formRef.current.formValues, key)) !== null && _a !== void 0 ? _a : defaultValue;
1306
- subscriptions.current.set(key, val);
1307
- return subscriptions.current.get(key);
1308
- },
1309
- // eslint-disable-next-line react-hooks/exhaustive-deps
1310
- [trigger]);
1311
- const set = useCallback((field, value) => {
1312
- formRef.current.setValue(field, value);
1313
- }, []);
1314
- return {
1315
- get,
1316
- set
1317
- };
1318
- };const trimObject = obj => Object.entries(obj !== null && obj !== void 0 ? obj : {}).reduce((prev, [key, val]) => Object.assign(Object.assign({}, prev), {
1319
- [key]: typeof val === 'string' && !['password', 'pPassword'].includes(key) ? val.trim() : val
1320
- }), {});
1321
- const RenderField = t0 => {
1322
- const $ = c(9);
1323
- const {
1324
- field,
1325
- fieldState,
1326
- fieldProps,
1327
- onFieldChange
1328
- } = t0;
1329
- let t1;
1330
- if ($[0] !== field || $[1] !== fieldProps || $[2] !== fieldState) {
1331
- t1 = Object.assign(Object.assign({}, fieldProps), {
1332
- field,
1333
- fieldState
1334
- });
1335
- $[0] = field;
1336
- $[1] = fieldProps;
1337
- $[2] = fieldState;
1338
- $[3] = t1;
1339
- } else {
1340
- t1 = $[3];
1341
- }
1342
- const config = t1;
1343
- let t2;
1344
- if ($[4] !== config || $[5] !== fieldProps.errorNs || $[6] !== fieldProps.ns || $[7] !== onFieldChange) {
1345
- t2 = jsx(FormField, {
1346
- config,
1347
- ns: fieldProps.ns,
1348
- globalErrorNs: fieldProps.errorNs,
1349
- onFieldChange
1350
- });
1351
- $[4] = config;
1352
- $[5] = fieldProps.errorNs;
1353
- $[6] = fieldProps.ns;
1354
- $[7] = onFieldChange;
1355
- $[8] = t2;
1356
- } else {
1357
- t2 = $[8];
1358
- }
1359
- return t2;
1360
- };
1361
- const DynamicFieldItem = ({
1362
- item,
1363
- form,
1364
- globalErrorNs,
1365
- formId
1366
- }) => {
1367
- const {
1368
- get,
1369
- set
1370
- } = useFormValues({
1371
- formId
1372
- });
1373
- const fieldProps = useMemo(() => {
1374
- if (typeof item === 'function') {
1375
- return item({
1376
- get,
1377
- set
1378
- });
1379
- } else {
1380
- return item;
1381
- }
1382
- }, [get, set, item]);
1383
- const isHidden = useMemo(() => {
1384
- if (!fieldProps.hidden) {
1385
- return false;
1386
- } else if (typeof fieldProps.hidden === 'function') {
1387
- return fieldProps.hidden({
1388
- get,
1389
- set
1390
- });
1391
- } else {
1392
- return !!fieldProps.hidden;
1393
- }
1394
- }, [get, set, fieldProps]);
1395
- const rules = useMemo(() => {
1396
- if (!fieldProps.rules) {
1397
- return undefined;
1398
- } else if (typeof fieldProps.rules === 'function') {
1399
- return fieldProps.rules({
1400
- get,
1401
- set
1402
- });
1403
- } else {
1404
- return fieldProps.rules;
1405
- }
1406
- }, [get, set, fieldProps]);
1407
- const props = useMemo(() => {
1408
- var _a;
1409
- return Object.assign(Object.assign({}, fieldProps), {
1410
- errorNs: (_a = fieldProps.errorNs) !== null && _a !== void 0 ? _a : globalErrorNs
1411
- });
1412
- }, [fieldProps, globalErrorNs]);
1413
- if (isHidden) {
1414
- return jsx(Fragment, {});
1415
- }
1416
- return jsx(form.Field, {
1417
- name: props.name,
1418
- validators: rules,
1419
- // eslint-disable-next-line react/no-children-prop
1420
- children: field => jsx(RenderField, {
1421
- field: field,
1422
- fieldState: field.state,
1423
- fieldProps: props,
1424
- onFieldChange: props.onFieldChange
1425
- })
1426
- });
1427
- };
1428
- const SubmitItem = ({
1429
- item,
1430
- index,
1431
- handlersRef
1432
- }) => {
1433
- const handleClick = useCallback(async () => {
1434
- const {
1435
- formControl,
1436
- createSubmitHandler,
1437
- onInvalidHandle
1438
- } = handlersRef.current;
1439
- // Partial or full validation logic
1440
- let isValid = true;
1441
- const keys = item.values;
1442
- if (keys && keys.length > 0) {
1443
- // Validate only specific fields
1444
- await Promise.all(keys.map(key => formControl.validateField(key, 'change')));
1445
- const hasError = keys.some(key_0 => {
1446
- // This is a simplified check. TanStack form errors might be structured differently.
1447
- // You might need deep checking if errors are nested objects.
1448
- // For now assume flat or use lodash get if possible, but state.errors is usually flat-ish map in newer versions or object.
1449
- // Checking standard TanStack: form.state.fieldMeta[key]?.errors
1450
- const meta = formControl.getFieldMeta(key_0);
1451
- return (meta === null || meta === void 0 ? void 0 : meta.errors) && meta.errors.length > 0;
1452
- });
1453
- isValid = !hasError;
1454
- } else {
1455
- // Validate all
1456
- await formControl.validateAllFields('submit');
1457
- isValid = formControl.state.isValid;
1458
- }
1459
- if (!isValid) {
1460
- onInvalidHandle(formControl.state.errors, item);
1461
- return;
1462
- }
1463
- const values = formControl.state.values;
1464
- // Call handlers
1465
- await createSubmitHandler(item)(values);
1466
- }, [item, handlersRef]);
1467
- const Component = useMemo(() => item.component, [item]);
1468
- if (item.hidden || !Component) return jsx(Fragment, {});
1469
- return jsx(Component, {
1470
- onClick: handleClick,
1471
- index: index,
1472
- type: item.type || 'button'
1473
- }, `submit-${index}`);
1474
- };
1475
- const useFormManager = ({
1476
- data,
1477
- onInvalid,
1478
- submit = [],
1479
- notification,
1480
- formOptions,
1481
- onValuesChange,
1482
- globalErrorNs,
1483
- id = 'form-manager'
1484
- }) => {
1485
- const formControl = useJotaiForm(formOptions);
1486
- const formState = useMemo(() => formControl.state, [formControl.state]);
1487
- const errors = useMemo(() => formState.errors, [formState.errors]);
1488
- const values = useMemo(() => formState.values, [formState.values]);
1489
- const setFormState = useSetFormState(id);
1490
- const {
1491
- showNotification
1492
- } = useFormConfigValue();
1493
- const setValue = useCallback((field, updater) => formControl.setFieldValue(field, updater), [formControl]);
1494
- useEffect(() => {
1495
- setFormState({
1496
- setValue,
1497
- formValues: formState.values
1498
- });
1499
- const unsubscribe = formControl.store.subscribe(store => {
1500
- setFormState({
1501
- formValues: store.currentVal.values
1502
- });
1503
- });
1504
- return () => {
1505
- unsubscribe();
1506
- }; /**/
1507
- }, [formControl.store, setValue, formState.values, setFormState]);
1508
- const handleNotification = useCallback(props => {
1509
- if (props.message) {
1510
- showNotification === null || showNotification === void 0 ? void 0 : showNotification(props);
1511
- }
1512
- }, [showNotification]);
1513
- const filterFormData = useCallback((v, submitConfig) => {
1514
- const keys = submitConfig.values;
1515
- if (!keys || keys.length === 0) {
1516
- return v;
1517
- }
1518
- const out = {};
1519
- for (const key of keys) {
1520
- if (key in v) {
1521
- out[key] = v[key];
1522
- }
1523
- }
1524
- return out;
1525
- }, []);
1526
- const processSubmit = useCallback(async (d, submitConfig_0) => {
1527
- const filteredData = filterFormData(d, submitConfig_0);
1528
- if (submitConfig_0.onSuccess) {
1529
- return await submitConfig_0.onSuccess(filteredData);
1530
- }
1531
- throw new Error('No submit handler provided');
1532
- }, [filterFormData]);
1533
- const handleError = useCallback((error, submitConfig_1) => {
1534
- if (submitConfig_1.onError) {
1535
- submitConfig_1.onError(error);
1536
- }
1537
- const notificationProps = typeof (notification === null || notification === void 0 ? void 0 : notification.error) === 'function' ? notification.error(error.message) : notification === null || notification === void 0 ? void 0 : notification.error;
1538
- if (notificationProps === null || notificationProps === void 0 ? void 0 : notificationProps.message) {
1539
- handleNotification(notificationProps);
1540
- }
1541
- }, [handleNotification, notification]);
1542
- const createSubmitHandler = useCallback(submitConfig_2 => async dataSubmit => {
1543
- try {
1544
- const res = await processSubmit(trimObject(dataSubmit), submitConfig_2);
1545
- const notificationProps_0 = typeof (notification === null || notification === void 0 ? void 0 : notification.success) === 'function' ? notification.success(res) : notification === null || notification === void 0 ? void 0 : notification.success;
1546
- if (notificationProps_0 === null || notificationProps_0 === void 0 ? void 0 : notificationProps_0.message) {
1547
- handleNotification(notificationProps_0);
1548
- }
1549
- return res;
1550
- } catch (error_0) {
1551
- handleError(error_0, submitConfig_2);
1552
- throw error_0;
1553
- }
1554
- }, [processSubmit, notification, handleNotification, handleError]);
1555
- const onInvalidHandle = useCallback((err, submitConfig_3) => {
1556
- onInvalid === null || onInvalid === void 0 ? void 0 : onInvalid(err);
1557
- handleError(new Error('invalidData'), submitConfig_3);
1558
- }, [handleError, onInvalid]);
1559
- const handlersRef = useRef({
1560
- formControl,
1561
- onInvalidHandle,
1562
- createSubmitHandler,
1563
- setValue: formControl.setFieldValue,
1564
- trigger: formControl.validateField,
1565
- onValuesChange
1566
- });
1567
- useEffect(() => {
1568
- handlersRef.current.onInvalidHandle = onInvalidHandle;
1569
- handlersRef.current.createSubmitHandler = createSubmitHandler;
1570
- handlersRef.current.setValue = formControl.setFieldValue;
1571
- handlersRef.current.trigger = formControl.validateField;
1572
- handlersRef.current.onValuesChange = onValuesChange;
1573
- }, [onInvalidHandle, createSubmitHandler, formControl, onValuesChange]);
1574
- const fields = useMemo(() => data.map((item, index) => {
1575
- var _a, _b;
1576
- const staticItem = typeof item === 'function' ? null : item;
1577
- return {
1578
- index: (_a = staticItem === null || staticItem === void 0 ? void 0 : staticItem.index) !== null && _a !== void 0 ? _a : index,
1579
- element: jsx(DynamicFieldItem, {
1580
- item: item,
1581
- form: formControl,
1582
- globalErrorNs: globalErrorNs,
1583
- formId: id
1584
- }, (_b = staticItem === null || staticItem === void 0 ? void 0 : staticItem.name) !== null && _b !== void 0 ? _b : index),
1585
- renderInFooter: !!(staticItem === null || staticItem === void 0 ? void 0 : staticItem.renderInFooter),
1586
- renderInHeader: !!(staticItem === null || staticItem === void 0 ? void 0 : staticItem.renderInHeader)
1587
- };
1588
- }), [data, formControl, globalErrorNs, id]);
1589
- const submits = useMemo(() => submit.map((submitConfig_4, index_0) => {
1590
- return {
1591
- index: submitConfig_4.index === undefined ? index_0 : submitConfig_4.index,
1592
- element: jsx(SubmitItem, {
1593
- item: submitConfig_4,
1594
- index: index_0,
1595
- handlersRef: handlersRef
1596
- }, `submit-${index_0}`),
1597
- renderInFooter: !!submitConfig_4.renderInFooter,
1598
- renderInHeader: !!submitConfig_4.renderInHeader,
1599
- isSubmit: true
1600
- };
1601
- }), [submit]);
1602
- const elements = useMemo(() => fields.concat(submits), [fields, submits]);
1603
- const formContents = useMemo(() => [...data, ...submit], [data, submit]);
1604
- useEffect(() => {
1605
- var _a_0, _b_0;
1606
- (_b_0 = (_a_0 = handlersRef.current).onValuesChange) === null || _b_0 === void 0 ? void 0 : _b_0.call(_a_0, values, handlersRef.current.setValue);
1607
- }, [values]);
1608
- return {
1609
- elements,
1610
- formContents,
1611
- errors,
1612
- formValues: values,
1613
- setValue
1614
- };
1615
28
  };/* eslint-disable @typescript-eslint/no-explicit-any */
1616
29
  /**
1617
30
  * Optimized shallow equality check for objects and functions
@@ -2887,9 +1300,9 @@ let _pageConfig = {
2887
1300
  HeaderContainer: DefaultContainer,
2888
1301
  FooterContainer: DefaultContainer,
2889
1302
  BodyContainer: DefaultContainer,
2890
- authPageImage: '',
1303
+ authPageImage: "",
2891
1304
  authPageProps: {
2892
- id: 'auth-page'
1305
+ id: "auth-page"
2893
1306
  },
2894
1307
  isLogged: val => !!(val === null || val === void 0 ? void 0 : val.id) && !!val.isLogged,
2895
1308
  ItemsContainer: ({
@@ -2899,8 +1312,8 @@ let _pageConfig = {
2899
1312
  children
2900
1313
  }) => children,
2901
1314
  meta: {
2902
- title: '',
2903
- description: ''
1315
+ title: "",
1316
+ description: ""
2904
1317
  },
2905
1318
  // Metadata configuration
2906
1319
  defaultMetadata: {},
@@ -2913,7 +1326,7 @@ let _pageConfig = {
2913
1326
  preloadOnHover: false,
2914
1327
  preloadOnFocus: false,
2915
1328
  timeout: 30000,
2916
- logMetrics: process.env.NODE_ENV === 'development'
1329
+ logMetrics: process.env.NODE_ENV === "development"
2917
1330
  }
2918
1331
  };
2919
1332
  /**
@@ -2925,9 +1338,9 @@ function initializePageConfig() {
2925
1338
  HeaderContainer: DefaultContainer,
2926
1339
  FooterContainer: DefaultContainer,
2927
1340
  BodyContainer: DefaultContainer,
2928
- authPageImage: '',
1341
+ authPageImage: "",
2929
1342
  authPageProps: {
2930
- id: 'auth-page'
1343
+ id: "auth-page"
2931
1344
  },
2932
1345
  isLogged: val => !!(val === null || val === void 0 ? void 0 : val.id) && !!val.isLogged,
2933
1346
  ItemsContainer: ({
@@ -2937,8 +1350,8 @@ function initializePageConfig() {
2937
1350
  children
2938
1351
  }) => children,
2939
1352
  meta: {
2940
- title: '',
2941
- description: ''
1353
+ title: "",
1354
+ description: ""
2942
1355
  },
2943
1356
  // Metadata configuration
2944
1357
  defaultMetadata: {},
@@ -2951,7 +1364,7 @@ function initializePageConfig() {
2951
1364
  preloadOnHover: false,
2952
1365
  preloadOnFocus: false,
2953
1366
  timeout: 30000,
2954
- logMetrics: process.env.NODE_ENV === 'development'
1367
+ logMetrics: process.env.NODE_ENV === "development"
2955
1368
  }
2956
1369
  };
2957
1370
  return _pageConfig;
@@ -2966,7 +1379,7 @@ const {
2966
1379
  useState: usePageConfigState,
2967
1380
  useReset: usePageConfigReset
2968
1381
  } = atomStateGenerator({
2969
- key: 'pageConfig',
1382
+ key: "pageConfig",
2970
1383
  defaultValue: _pageConfig,
2971
1384
  persist: false
2972
1385
  });/**