@faasjs/react 7.0.0 → 7.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -65,12 +65,12 @@ npm install @faasjs/react react
65
65
  ## Classes
66
66
 
67
67
  - [ErrorBoundary](classes/ErrorBoundary.md)
68
- - [Response](classes/Response.md)
69
- - [ResponseError](classes/ResponseError.md)
70
68
 
71
69
  ## Interfaces
72
70
 
73
71
  - [ErrorBoundaryProps](interfaces/ErrorBoundaryProps.md)
72
+ - [Response](interfaces/Response.md)
73
+ - [ResponseError](interfaces/ResponseError.md)
74
74
 
75
75
  ## Namespaces
76
76
 
package/dist/index.cjs CHANGED
@@ -1,18 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ var browser = require('@faasjs/browser');
3
4
  var react = require('react');
4
5
  var jsxRuntime = require('react/jsx-runtime');
5
- var browser = require('@faasjs/browser');
6
6
 
7
- // src/constant.ts
8
- function useConstant(fn) {
9
- const ref = react.useRef(null);
10
- if (!ref.current) {
11
- ref.current = { v: fn() };
12
- }
13
- return ref.current.v;
14
- }
15
- useConstant.whyDidYouRender = true;
7
+ // src/client.tsx
16
8
  var AsyncFunction = (async () => {
17
9
  }).constructor;
18
10
  function equal(a, b) {
@@ -20,7 +12,8 @@ function equal(a, b) {
20
12
  if ((a === null || a === void 0) && (b === null || b === void 0))
21
13
  return true;
22
14
  if (typeof a !== typeof b) return false;
23
- if (b === null || b === void 0) return false;
15
+ if (a === null || a === void 0 || b === null || b === void 0)
16
+ return false;
24
17
  const ctor = a.constructor;
25
18
  if (ctor !== b.constructor) return false;
26
19
  switch (ctor) {
@@ -77,80 +70,6 @@ function useEqualCallback(callback, dependencies) {
77
70
  useEqualMemoize(dependencies)
78
71
  );
79
72
  }
80
- function useSplittingState(initialStates) {
81
- const states = {};
82
- for (const key of Object.keys(initialStates)) {
83
- const state = react.useState(initialStates[key]);
84
- Object.assign(states, {
85
- [key]: state[0],
86
- [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
87
- });
88
- }
89
- return states;
90
- }
91
- function createSplittingContext(defaultValue) {
92
- const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
93
- const defaultValues = Array.isArray(defaultValue) ? keys.reduce(
94
- (prev, cur) => {
95
- prev[cur] = null;
96
- return prev;
97
- },
98
- {}
99
- ) : defaultValue;
100
- const contexts = {};
101
- for (const key of keys) contexts[key] = react.createContext(defaultValues[key]);
102
- function Provider(props) {
103
- const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
104
- let children = props.memo ? useEqualMemo(
105
- () => props.children,
106
- props.memo === true ? [] : props.memo
107
- ) : props.children;
108
- for (const key of keys) {
109
- const Context = contexts[key];
110
- const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
111
- children = /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
112
- }
113
- return children;
114
- }
115
- Provider.displayName = "SplittingContextProvider";
116
- Provider.whyDidYouRender = true;
117
- function use() {
118
- return useConstant(() => {
119
- const obj = /* @__PURE__ */ Object.create(null);
120
- for (const key of Object.keys(contexts)) {
121
- Object.defineProperty(obj, key, {
122
- get: () => {
123
- if (!contexts[key]) {
124
- throw new Error(`Context for key "${key}" is undefined`);
125
- }
126
- return react.useContext(contexts[key]);
127
- }
128
- });
129
- }
130
- return Object.freeze(obj);
131
- });
132
- }
133
- use.whyDidYouRender = true;
134
- return {
135
- Provider,
136
- use
137
- };
138
- }
139
- function usePrevious(value) {
140
- const ref = react.useRef(void 0);
141
- react.useEffect(() => {
142
- ref.current = value;
143
- });
144
- return ref.current;
145
- }
146
- function useStateRef(initialValue) {
147
- const [state, setState] = react.useState(initialValue ?? null);
148
- const ref = react.useRef(state);
149
- react.useEffect(() => {
150
- ref.current = state;
151
- }, [state]);
152
- return [state, setState, ref];
153
- }
154
73
  var fixedForwardRef = react.forwardRef;
155
74
  var FaasDataWrapper = fixedForwardRef(
156
75
  (props, ref) => {
@@ -342,6 +261,14 @@ function getClient(host) {
342
261
  }
343
262
  return client;
344
263
  }
264
+ function useConstant(fn) {
265
+ const ref = react.useRef(null);
266
+ if (!ref.current) {
267
+ ref.current = { v: fn() };
268
+ }
269
+ return ref.current.v;
270
+ }
271
+ useConstant.whyDidYouRender = true;
345
272
  var ErrorBoundary = class extends react.Component {
346
273
  static displayName = "ErrorBoundary";
347
274
  static whyDidYouRender = true;
@@ -379,11 +306,73 @@ var ErrorBoundary = class extends react.Component {
379
306
  return this.props.children;
380
307
  }
381
308
  };
382
- var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
383
- return condition ? /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { ...wrapperProps, children }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
384
- };
385
- OptionalWrapper.displayName = "OptionalWrapper";
386
- OptionalWrapper.whyDidYouRender = true;
309
+ function useStateRef(initialValue) {
310
+ const [state, setState] = react.useState(initialValue ?? null);
311
+ const ref = react.useRef(state);
312
+ react.useEffect(() => {
313
+ ref.current = state;
314
+ }, [state]);
315
+ return [state, setState, ref];
316
+ }
317
+ function useSplittingState(initialStates) {
318
+ const states = {};
319
+ for (const key of Object.keys(initialStates)) {
320
+ const state = react.useState(initialStates[key]);
321
+ Object.assign(states, {
322
+ [key]: state[0],
323
+ [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
324
+ });
325
+ }
326
+ return states;
327
+ }
328
+ function createSplittingContext(defaultValue) {
329
+ const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
330
+ const defaultValues = Array.isArray(defaultValue) ? keys.reduce(
331
+ (prev, cur) => {
332
+ prev[cur] = null;
333
+ return prev;
334
+ },
335
+ {}
336
+ ) : defaultValue;
337
+ const contexts = {};
338
+ for (const key of keys) contexts[key] = react.createContext(defaultValues[key]);
339
+ function Provider(props) {
340
+ const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
341
+ let children = props.memo ? useEqualMemo(
342
+ () => props.children,
343
+ props.memo === true ? [] : props.memo
344
+ ) : props.children;
345
+ for (const key of keys) {
346
+ const Context = contexts[key];
347
+ const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
348
+ children = /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
349
+ }
350
+ return children;
351
+ }
352
+ Provider.displayName = "SplittingContextProvider";
353
+ Provider.whyDidYouRender = true;
354
+ function use() {
355
+ return useConstant(() => {
356
+ const obj = /* @__PURE__ */ Object.create(null);
357
+ for (const key of Object.keys(contexts)) {
358
+ Object.defineProperty(obj, key, {
359
+ get: () => {
360
+ if (!contexts[key]) {
361
+ throw new Error(`Context for key "${key}" is undefined`);
362
+ }
363
+ return react.useContext(contexts[key]);
364
+ }
365
+ });
366
+ }
367
+ return Object.freeze(obj);
368
+ });
369
+ }
370
+ use.whyDidYouRender = true;
371
+ return {
372
+ Provider,
373
+ use
374
+ };
375
+ }
387
376
 
388
377
  // src/Form/context.tsx
389
378
  var FormContext = createSplittingContext([
@@ -461,6 +450,45 @@ function FormBody() {
461
450
  }
462
451
  FormBody.displayName = "FormBody";
463
452
  FormBody.whyDidYouRender = true;
453
+ var FormButtonElement = react.forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
454
+ "button",
455
+ {
456
+ type: "button",
457
+ disabled: submitting,
458
+ onClick: submit,
459
+ ...props,
460
+ ref,
461
+ children
462
+ }
463
+ ));
464
+ FormButtonElement.displayName = "FormButtonElement";
465
+ Object.assign(FormButtonElement, { whyDidYouRender: true });
466
+ var FormInputElement = react.forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
467
+ FormInputElement.displayName = "FormInputElement";
468
+ Object.assign(FormInputElement, { whyDidYouRender: true });
469
+ var FormLabelElement = ({
470
+ name,
471
+ title,
472
+ description,
473
+ error,
474
+ children
475
+ }) => {
476
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
477
+ title ?? name,
478
+ children,
479
+ description,
480
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "red" }, children: error.message })
481
+ ] });
482
+ };
483
+ FormLabelElement.displayName = "FormLabelElement";
484
+ FormLabelElement.whyDidYouRender = true;
485
+
486
+ // src/Form/elements/index.ts
487
+ var FormDefaultElements = {
488
+ Label: FormLabelElement,
489
+ Input: FormInputElement,
490
+ Button: FormButtonElement
491
+ };
464
492
 
465
493
  // src/Form/rules.ts
466
494
  var FormDefaultRules = {
@@ -532,45 +560,6 @@ function FormFooter() {
532
560
  }
533
561
  FormFooter.displayName = "FormFooter";
534
562
  FormFooter.whyDidYouRender = true;
535
- var FormButtonElement = react.forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
536
- "button",
537
- {
538
- type: "button",
539
- disabled: submitting,
540
- onClick: submit,
541
- ...props,
542
- ref,
543
- children
544
- }
545
- ));
546
- FormButtonElement.displayName = "FormButtonElement";
547
- Object.assign(FormButtonElement, { whyDidYouRender: true });
548
- var FormInputElement = react.forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
549
- FormInputElement.displayName = "FormInputElement";
550
- Object.assign(FormInputElement, { whyDidYouRender: true });
551
- var FormLabelElement = ({
552
- name,
553
- title,
554
- description,
555
- error,
556
- children
557
- }) => {
558
- return /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
559
- title ?? name,
560
- children,
561
- description,
562
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "red" }, children: error.message })
563
- ] });
564
- };
565
- FormLabelElement.displayName = "FormLabelElement";
566
- FormLabelElement.whyDidYouRender = true;
567
-
568
- // src/Form/elements/index.ts
569
- var FormDefaultElements = {
570
- Label: FormLabelElement,
571
- Input: FormInputElement,
572
- Button: FormButtonElement
573
- };
574
563
 
575
564
  // src/Form/lang.ts
576
565
  var FormDefaultLang = {
@@ -623,6 +612,18 @@ function FormContainer({
623
612
  }
624
613
  FormContainer.displayName = "FormContainer";
625
614
  FormContainer.whyDidYouRender = true;
615
+ var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
616
+ return condition ? /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { ...wrapperProps, children }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
617
+ };
618
+ OptionalWrapper.displayName = "OptionalWrapper";
619
+ OptionalWrapper.whyDidYouRender = true;
620
+ function usePrevious(value) {
621
+ const ref = react.useRef(void 0);
622
+ react.useEffect(() => {
623
+ ref.current = value;
624
+ });
625
+ return ref.current;
626
+ }
626
627
 
627
628
  exports.ErrorBoundary = ErrorBoundary;
628
629
  exports.FaasDataWrapper = FaasDataWrapper;
package/dist/index.d.ts CHANGED
@@ -1,227 +1,11 @@
1
- import { FaasActionUnionType, FaasAction, FaasParams, FaasData } from '@faasjs/types';
2
- export { FaasAction, FaasData, FaasParams } from '@faasjs/types';
3
1
  import { Response, BaseUrl, ResponseError, Options, FaasBrowserClient } from '@faasjs/browser';
4
2
  export { Options, Response, ResponseError, ResponseHeaders } from '@faasjs/browser';
3
+ import { FaasActionUnionType, FaasAction, FaasParams, FaasData } from '@faasjs/types';
4
+ export { FaasAction, FaasData, FaasParams } from '@faasjs/types';
5
5
  import * as react from 'react';
6
- import { ReactNode, Dispatch, SetStateAction, RefObject, JSX, ReactElement, Component, ComponentType, ComponentProps, JSXElementConstructor } from 'react';
6
+ import { JSX, ReactNode, ReactElement, Component, ComponentType, JSXElementConstructor, ComponentProps, Dispatch, SetStateAction, RefObject } from 'react';
7
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
8
 
9
- /**
10
- * Returns a constant value that is created by the given function.
11
- */
12
- declare function useConstant<T>(fn: () => T): T;
13
- declare namespace useConstant {
14
- var whyDidYouRender: boolean;
15
- }
16
-
17
- /**
18
- * Compares two values for deep equality.
19
- *
20
- * This function checks if two values are deeply equal by comparing their types and contents.
21
- * It handles various data types including primitives, arrays, dates, regular expressions, functions,
22
- * maps, sets, and promises.
23
- *
24
- * @param a - The first value to compare.
25
- * @param b - The second value to compare.
26
- * @returns `true` if the values are deeply equal, `false` otherwise.
27
- */
28
- declare function equal(a: any, b: any): boolean;
29
- /**
30
- * Custom hook that memoizes a value using deep equality comparison.
31
- *
32
- * @param value - The value to be memoized.
33
- * @returns The memoized value.
34
- */
35
- declare function useEqualMemoize(value: any): any;
36
- /**
37
- * Custom hook that works like `useEffect` but uses deep comparison on dependencies.
38
- *
39
- * @param callback - The effect callback function to run.
40
- * @param dependencies - The list of dependencies for the effect.
41
- * @returns The result of the `useEffect` hook with memoized dependencies.
42
- */
43
- declare function useEqualEffect(callback: React.EffectCallback, dependencies: any[]): void;
44
- /**
45
- * Custom hook that works like `useMemo` but uses deep comparison on dependencies.
46
- *
47
- * @param callback - The callback function to run.
48
- * @param dependencies - The list of dependencies.
49
- * @returns The result of the `useMemo` hook with memoized dependencies.
50
- */
51
- declare function useEqualMemo<T>(callback: () => T, dependencies: any[]): T;
52
- /**
53
- * Custom hook that works like `useCallback` but uses deep comparison on dependencies.
54
- *
55
- * @param callback - The callback function to run.
56
- * @param dependencies - The list of dependencies.
57
- * @returns The result of the `useCallback` hook with memoized dependencies.
58
- */
59
- declare function useEqualCallback<T extends (...args: any[]) => any>(callback: T, dependencies: any[]): T;
60
-
61
- /**
62
- * Creates a splitting context with the given default value.
63
- *
64
- * @param defaultValue The default value of the splitting context.
65
- *
66
- * @example
67
- * ```tsx
68
- * const { Provider, use } = createSplittingContext<{
69
- * value: number
70
- * setValue: React.Dispatch<React.SetStateAction<number>>
71
- * }>({
72
- * value: 0,
73
- * setValue: null,
74
- * })
75
- *
76
- * function ReaderComponent() {
77
- * const { value } = use()
78
- *
79
- * return <div>{value}</div>
80
- * }
81
- *
82
- * function WriterComponent() {
83
- * const { setValue } = use()
84
- *
85
- * return (
86
- * <button type='button' onClick={() => setValue((p: number) => p + 1)}>
87
- * Change
88
- * </button>
89
- * )
90
- * }
91
- *
92
- * function App() {
93
- * const [value, setValue] = useState(0)
94
- *
95
- * return (
96
- * <Provider value={{ value, setValue }}>
97
- * <ReaderComponent />
98
- * <WriterComponent />
99
- * </Provider>
100
- * )
101
- * }
102
- * ```
103
- */
104
- declare function createSplittingContext<T extends Record<string, any>>(defaultValue: {
105
- [K in keyof T]: Partial<T[K]> | null;
106
- } | (keyof T)[]): {
107
- /**
108
- * The provider component of the splitting context.
109
- *
110
- * @see https://faasjs.com/doc/react/functions/createSplittingContext.html#provider
111
- *
112
- * @example
113
- * ```tsx
114
- * function App() {
115
- * const [value, setValue] = useState(0)
116
- *
117
- * return (
118
- * <Provider value={{ value, setValue }}>
119
- * <ReaderComponent />
120
- * <WriterComponent />
121
- * </Provider>
122
- * )
123
- * }
124
- * ```
125
- */
126
- Provider<NewT extends T = T>(props: {
127
- value?: Partial<NewT>;
128
- children: ReactNode;
129
- /**
130
- * Whether to use memoization for the children.
131
- *
132
- * @default false
133
- *
134
- * `true`: memoize the children without dependencies.
135
- * `any[]`: memoize the children with specific dependencies.
136
- */
137
- memo?: true | any[];
138
- /**
139
- * An object containing initial values that will be automatically converted into state variables using {@link useSplittingState} hook. Each property will create both a state value and its setter following the pattern: value/setValue.
140
- *
141
- * @example
142
- * ```tsx
143
- * <Provider
144
- * initializeStates={{
145
- * value: 0,
146
- * }}
147
- * >
148
- * // Children will have access to: value, setValue
149
- * </Provider>
150
- */
151
- initializeStates?: Partial<NewT>;
152
- }): ReactNode;
153
- /**
154
- * The hook to use the splitting context.
155
- *
156
- * @see https://faasjs.com/doc/react/functions/createSplittingContext.html#use
157
- *
158
- * @example
159
- * ```tsx
160
- * function ChildComponent() {
161
- * const { value, setValue } = use()
162
- *
163
- * return <div>{value}<button onClick={() => setValue(1)}>change value</button></div>
164
- * }
165
- * ```
166
- */
167
- use: <NewT extends T = T>() => Readonly<NewT>;
168
- };
169
-
170
- type SetPrefix<S extends string | number | symbol> = S extends string ? S extends `${infer First}${infer Rest}` ? `set${Capitalize<First>}${Rest}` : never : never;
171
- type StateSetters<T> = {
172
- [K in keyof T as SetPrefix<K>]: Dispatch<SetStateAction<T[K]>>;
173
- };
174
- type StatesWithSetters<T> = T & StateSetters<T>;
175
- /**
176
- * A hook that initializes and splits state variables and their corresponding setters.
177
- *
178
- * @template T - A generic type that extends a record with string keys and any values.
179
- * @param {T} initialStates - An object containing the initial states.
180
- *
181
- * @example
182
- * ```tsx
183
- * function Counter() {
184
- * const { count, setCount, name, setName } = useSplittingState({ count: 0, name: 'John' });
185
- *
186
- * return <>{name}: {count}</>
187
- * }
188
- * ```
189
- */
190
- declare function useSplittingState<T extends Record<string, unknown>>(initialStates: T): StatesWithSetters<T>;
191
-
192
- /**
193
- * Hook to store the previous value of a state or prop.
194
- *
195
- * @template T - The type of the value.
196
- * @param {T} value - The current value to be stored.
197
- * @returns {T | undefined} - The previous value, or undefined if there is no previous value.
198
- */
199
- declare function usePrevious<T = any>(value: T): T | undefined;
200
-
201
- /**
202
- * Custom hook that returns a stateful value and a ref to that value.
203
- *
204
- * @template T - The type of the value.
205
- * @param {T} initialValue - The initial value of the state.
206
- * @returns {[T, (value: T) => void, RefObject<T>]} - The stateful value, a function to set the value, and a ref to the value.
207
- *
208
- * @example
209
- * ```tsx
210
- * import { useStateRef } from '@faasjs/react'
211
- *
212
- * function MyComponent() {
213
- * const [value, setValue, ref] = useStateRef(0)
214
- *
215
- * return (
216
- * <div>
217
- * <p>Value: {value}</p>
218
- * <button onClick={() => setValue(value + 1)}>Increment</button>
219
- * <button onClick={() => console.log(ref.current)}>Submit</button>
220
- * </div>
221
- * )
222
- */
223
- declare function useStateRef<T = any>(initialValue?: T): [T, Dispatch<SetStateAction<T>>, RefObject<T>];
224
-
225
9
  /**
226
10
  * Injects FaasData props.
227
11
  */
@@ -358,20 +142,12 @@ declare function FaasReactClient({ baseUrl, options, onError }?: FaasReactClient
358
142
  declare function getClient(host?: string): FaasReactClientInstance;
359
143
 
360
144
  /**
361
- * Request faas server
362
- *
363
- * @param action {string} action name
364
- * @param params {object} action params
365
- * @returns {Promise<Response<any>>}
366
- *
367
- * @example
368
- * ```ts
369
- * faas<{ title: string }>('post/get', { id: 1 }).then(res => {
370
- * console.log(res.data.title)
371
- * })
372
- * ```
145
+ * Returns a constant value that is created by the given function.
373
146
  */
374
- declare function faas<PathOrData extends FaasActionUnionType>(action: FaasAction<PathOrData>, params: FaasParams<PathOrData>, options?: Options): Promise<Response<FaasData<PathOrData>>>;
147
+ declare function useConstant<T>(fn: () => T): T;
148
+ declare namespace useConstant {
149
+ var whyDidYouRender: boolean;
150
+ }
375
151
 
376
152
  interface ErrorBoundaryProps {
377
153
  children?: ReactNode;
@@ -394,38 +170,52 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, {
394
170
  static whyDidYouRender: boolean;
395
171
  constructor(props: ErrorBoundaryProps);
396
172
  componentDidCatch(error: Error | null, info: any): void;
397
- render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode>> | react_jsx_runtime.JSX.Element;
173
+ render(): string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode>>;
398
174
  }
399
175
 
400
- type OptionalWrapperProps<TWrapper extends ComponentType<{
401
- children: ReactNode;
402
- }> = any> = {
403
- condition: boolean;
404
- Wrapper: TWrapper;
405
- wrapperProps?: ComponentProps<TWrapper>;
406
- children: ReactNode;
407
- };
408
176
  /**
409
- * A wrapper component that conditionally wraps its children with a provided wrapper component.
177
+ * Compares two values for deep equality.
410
178
  *
411
- * @example
412
- * ```tsx
413
- * import { OptionalWrapper } from '@faasjs/react'
179
+ * This function checks if two values are deeply equal by comparing their types and contents.
180
+ * It handles various data types including primitives, arrays, dates, regular expressions, functions,
181
+ * maps, sets, and promises.
414
182
  *
415
- * const Wrapper = ({ children }: { children: React.ReactNode }) => (
416
- * <div className='wrapper'>{children}</div>
417
- * )
183
+ * @param a - The first value to compare.
184
+ * @param b - The second value to compare.
185
+ * @returns `true` if the values are deeply equal, `false` otherwise.
186
+ */
187
+ declare function equal(a: any, b: any): boolean;
188
+ /**
189
+ * Custom hook that memoizes a value using deep equality comparison.
418
190
  *
419
- * const App = () => (
420
- * <OptionalWrapper condition={true} Wrapper={Wrapper}>
421
- * <span>Test</span>
422
- * </OptionalWrapper>
423
- * )
424
- * ```
191
+ * @param value - The value to be memoized.
192
+ * @returns The memoized value.
425
193
  */
426
- declare const OptionalWrapper: React.FC<OptionalWrapperProps> & {
427
- whyDidYouRender: boolean;
428
- };
194
+ declare function useEqualMemoize(value: any): any;
195
+ /**
196
+ * Custom hook that works like `useEffect` but uses deep comparison on dependencies.
197
+ *
198
+ * @param callback - The effect callback function to run.
199
+ * @param dependencies - The list of dependencies for the effect.
200
+ * @returns The result of the `useEffect` hook with memoized dependencies.
201
+ */
202
+ declare function useEqualEffect(callback: React.EffectCallback, dependencies: any[]): void;
203
+ /**
204
+ * Custom hook that works like `useMemo` but uses deep comparison on dependencies.
205
+ *
206
+ * @param callback - The callback function to run.
207
+ * @param dependencies - The list of dependencies.
208
+ * @returns The result of the `useMemo` hook with memoized dependencies.
209
+ */
210
+ declare function useEqualMemo<T>(callback: () => T, dependencies: any[]): T;
211
+ /**
212
+ * Custom hook that works like `useCallback` but uses deep comparison on dependencies.
213
+ *
214
+ * @param callback - The callback function to run.
215
+ * @param dependencies - The list of dependencies.
216
+ * @returns The result of the `useCallback` hook with memoized dependencies.
217
+ */
218
+ declare function useEqualCallback<T extends (...args: any[]) => any>(callback: T, dependencies: any[]): T;
429
219
 
430
220
  /**
431
221
  * Props for the FormButtonElement component.
@@ -624,4 +414,214 @@ declare const FormContextProvider: <NewT extends FormContextProps<Record<string,
624
414
  }) => react.ReactNode;
625
415
  declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>() => Readonly<NewT>;
626
416
 
417
+ /**
418
+ * Request faas server
419
+ *
420
+ * @param action {string} action name
421
+ * @param params {object} action params
422
+ * @returns {Promise<Response<any>>}
423
+ *
424
+ * @example
425
+ * ```ts
426
+ * faas<{ title: string }>('post/get', { id: 1 }).then(res => {
427
+ * console.log(res.data.title)
428
+ * })
429
+ * ```
430
+ */
431
+ declare function faas<PathOrData extends FaasActionUnionType>(action: FaasAction<PathOrData>, params: FaasParams<PathOrData>, options?: Options): Promise<Response<FaasData<PathOrData>>>;
432
+
433
+ type OptionalWrapperProps<TWrapper extends ComponentType<{
434
+ children: ReactNode;
435
+ }> = any> = {
436
+ condition: boolean;
437
+ Wrapper: TWrapper;
438
+ wrapperProps?: ComponentProps<TWrapper>;
439
+ children: ReactNode;
440
+ };
441
+ /**
442
+ * A wrapper component that conditionally wraps its children with a provided wrapper component.
443
+ *
444
+ * @example
445
+ * ```tsx
446
+ * import { OptionalWrapper } from '@faasjs/react'
447
+ *
448
+ * const Wrapper = ({ children }: { children: React.ReactNode }) => (
449
+ * <div className='wrapper'>{children}</div>
450
+ * )
451
+ *
452
+ * const App = () => (
453
+ * <OptionalWrapper condition={true} Wrapper={Wrapper}>
454
+ * <span>Test</span>
455
+ * </OptionalWrapper>
456
+ * )
457
+ * ```
458
+ */
459
+ declare const OptionalWrapper: React.FC<OptionalWrapperProps> & {
460
+ whyDidYouRender: boolean;
461
+ };
462
+
463
+ /**
464
+ * Creates a splitting context with the given default value.
465
+ *
466
+ * @param defaultValue The default value of the splitting context.
467
+ *
468
+ * @example
469
+ * ```tsx
470
+ * const { Provider, use } = createSplittingContext<{
471
+ * value: number
472
+ * setValue: React.Dispatch<React.SetStateAction<number>>
473
+ * }>({
474
+ * value: 0,
475
+ * setValue: null,
476
+ * })
477
+ *
478
+ * function ReaderComponent() {
479
+ * const { value } = use()
480
+ *
481
+ * return <div>{value}</div>
482
+ * }
483
+ *
484
+ * function WriterComponent() {
485
+ * const { setValue } = use()
486
+ *
487
+ * return (
488
+ * <button type='button' onClick={() => setValue((p: number) => p + 1)}>
489
+ * Change
490
+ * </button>
491
+ * )
492
+ * }
493
+ *
494
+ * function App() {
495
+ * const [value, setValue] = useState(0)
496
+ *
497
+ * return (
498
+ * <Provider value={{ value, setValue }}>
499
+ * <ReaderComponent />
500
+ * <WriterComponent />
501
+ * </Provider>
502
+ * )
503
+ * }
504
+ * ```
505
+ */
506
+ declare function createSplittingContext<T extends Record<string, any>>(defaultValue: {
507
+ [K in keyof T]: Partial<T[K]> | null;
508
+ } | (keyof T)[]): {
509
+ /**
510
+ * The provider component of the splitting context.
511
+ *
512
+ * @see https://faasjs.com/doc/react/functions/createSplittingContext.html#provider
513
+ *
514
+ * @example
515
+ * ```tsx
516
+ * function App() {
517
+ * const [value, setValue] = useState(0)
518
+ *
519
+ * return (
520
+ * <Provider value={{ value, setValue }}>
521
+ * <ReaderComponent />
522
+ * <WriterComponent />
523
+ * </Provider>
524
+ * )
525
+ * }
526
+ * ```
527
+ */
528
+ Provider<NewT extends T = T>(props: {
529
+ value?: Partial<NewT>;
530
+ children: ReactNode;
531
+ /**
532
+ * Whether to use memoization for the children.
533
+ *
534
+ * @default false
535
+ *
536
+ * `true`: memoize the children without dependencies.
537
+ * `any[]`: memoize the children with specific dependencies.
538
+ */
539
+ memo?: true | any[];
540
+ /**
541
+ * An object containing initial values that will be automatically converted into state variables using {@link useSplittingState} hook. Each property will create both a state value and its setter following the pattern: value/setValue.
542
+ *
543
+ * @example
544
+ * ```tsx
545
+ * <Provider
546
+ * initializeStates={{
547
+ * value: 0,
548
+ * }}
549
+ * >
550
+ * // Children will have access to: value, setValue
551
+ * </Provider>
552
+ */
553
+ initializeStates?: Partial<NewT>;
554
+ }): ReactNode;
555
+ /**
556
+ * The hook to use the splitting context.
557
+ *
558
+ * @see https://faasjs.com/doc/react/functions/createSplittingContext.html#use
559
+ *
560
+ * @example
561
+ * ```tsx
562
+ * function ChildComponent() {
563
+ * const { value, setValue } = use()
564
+ *
565
+ * return <div>{value}<button onClick={() => setValue(1)}>change value</button></div>
566
+ * }
567
+ * ```
568
+ */
569
+ use: <NewT extends T = T>() => Readonly<NewT>;
570
+ };
571
+
572
+ type SetPrefix<S extends string | number | symbol> = S extends string ? S extends `${infer First}${infer Rest}` ? `set${Capitalize<First>}${Rest}` : never : never;
573
+ type StateSetters<T> = {
574
+ [K in keyof T as SetPrefix<K>]: Dispatch<SetStateAction<T[K]>>;
575
+ };
576
+ type StatesWithSetters<T> = T & StateSetters<T>;
577
+ /**
578
+ * A hook that initializes and splits state variables and their corresponding setters.
579
+ *
580
+ * @template T - A generic type that extends a record with string keys and any values.
581
+ * @param {T} initialStates - An object containing the initial states.
582
+ *
583
+ * @example
584
+ * ```tsx
585
+ * function Counter() {
586
+ * const { count, setCount, name, setName } = useSplittingState({ count: 0, name: 'John' });
587
+ *
588
+ * return <>{name}: {count}</>
589
+ * }
590
+ * ```
591
+ */
592
+ declare function useSplittingState<T extends Record<string, unknown>>(initialStates: T): StatesWithSetters<T>;
593
+
594
+ /**
595
+ * Hook to store the previous value of a state or prop.
596
+ *
597
+ * @template T - The type of the value.
598
+ * @param {T} value - The current value to be stored.
599
+ * @returns {T | undefined} - The previous value, or undefined if there is no previous value.
600
+ */
601
+ declare function usePrevious<T = any>(value: T): T | undefined;
602
+
603
+ /**
604
+ * Custom hook that returns a stateful value and a ref to that value.
605
+ *
606
+ * @template T - The type of the value.
607
+ * @param {T} initialValue - The initial value of the state.
608
+ * @returns {[T, (value: T) => void, RefObject<T>]} - The stateful value, a function to set the value, and a ref to the value.
609
+ *
610
+ * @example
611
+ * ```tsx
612
+ * import { useStateRef } from '@faasjs/react'
613
+ *
614
+ * function MyComponent() {
615
+ * const [value, setValue, ref] = useStateRef(0)
616
+ *
617
+ * return (
618
+ * <div>
619
+ * <p>Value: {value}</p>
620
+ * <button onClick={() => setValue(value + 1)}>Increment</button>
621
+ * <button onClick={() => console.log(ref.current)}>Submit</button>
622
+ * </div>
623
+ * )
624
+ */
625
+ declare function useStateRef<T = any>(initialValue?: T): [T, Dispatch<SetStateAction<T>>, RefObject<T>];
626
+
627
627
  export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, type FaasDataWrapperRef, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, type FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, type FormDefaultRulesOptions, type FormElementTypes, type FormInputElementProps, FormItem, type FormItemName, type FormItemProps, type FormLabelElementProps, type FormLang, type FormProps, type FormRule, type FormRules, type InferFormRulesOptions, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
package/dist/index.mjs CHANGED
@@ -1,16 +1,8 @@
1
- import { forwardRef, useState, useImperativeHandle, cloneElement, useEffect, useMemo, createContext, useRef, useCallback, useContext, Component } from 'react';
2
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
1
  import { FaasBrowserClient } from '@faasjs/browser';
2
+ import { forwardRef, useState, useImperativeHandle, cloneElement, useEffect, useMemo, createContext, useRef, useCallback, Component, useContext } from 'react';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
 
5
- // src/constant.ts
6
- function useConstant(fn) {
7
- const ref = useRef(null);
8
- if (!ref.current) {
9
- ref.current = { v: fn() };
10
- }
11
- return ref.current.v;
12
- }
13
- useConstant.whyDidYouRender = true;
5
+ // src/client.tsx
14
6
  var AsyncFunction = (async () => {
15
7
  }).constructor;
16
8
  function equal(a, b) {
@@ -18,7 +10,8 @@ function equal(a, b) {
18
10
  if ((a === null || a === void 0) && (b === null || b === void 0))
19
11
  return true;
20
12
  if (typeof a !== typeof b) return false;
21
- if (b === null || b === void 0) return false;
13
+ if (a === null || a === void 0 || b === null || b === void 0)
14
+ return false;
22
15
  const ctor = a.constructor;
23
16
  if (ctor !== b.constructor) return false;
24
17
  switch (ctor) {
@@ -75,80 +68,6 @@ function useEqualCallback(callback, dependencies) {
75
68
  useEqualMemoize(dependencies)
76
69
  );
77
70
  }
78
- function useSplittingState(initialStates) {
79
- const states = {};
80
- for (const key of Object.keys(initialStates)) {
81
- const state = useState(initialStates[key]);
82
- Object.assign(states, {
83
- [key]: state[0],
84
- [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
85
- });
86
- }
87
- return states;
88
- }
89
- function createSplittingContext(defaultValue) {
90
- const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
91
- const defaultValues = Array.isArray(defaultValue) ? keys.reduce(
92
- (prev, cur) => {
93
- prev[cur] = null;
94
- return prev;
95
- },
96
- {}
97
- ) : defaultValue;
98
- const contexts = {};
99
- for (const key of keys) contexts[key] = createContext(defaultValues[key]);
100
- function Provider(props) {
101
- const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
102
- let children = props.memo ? useEqualMemo(
103
- () => props.children,
104
- props.memo === true ? [] : props.memo
105
- ) : props.children;
106
- for (const key of keys) {
107
- const Context = contexts[key];
108
- const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
109
- children = /* @__PURE__ */ jsx(Context.Provider, { value, children });
110
- }
111
- return children;
112
- }
113
- Provider.displayName = "SplittingContextProvider";
114
- Provider.whyDidYouRender = true;
115
- function use() {
116
- return useConstant(() => {
117
- const obj = /* @__PURE__ */ Object.create(null);
118
- for (const key of Object.keys(contexts)) {
119
- Object.defineProperty(obj, key, {
120
- get: () => {
121
- if (!contexts[key]) {
122
- throw new Error(`Context for key "${key}" is undefined`);
123
- }
124
- return useContext(contexts[key]);
125
- }
126
- });
127
- }
128
- return Object.freeze(obj);
129
- });
130
- }
131
- use.whyDidYouRender = true;
132
- return {
133
- Provider,
134
- use
135
- };
136
- }
137
- function usePrevious(value) {
138
- const ref = useRef(void 0);
139
- useEffect(() => {
140
- ref.current = value;
141
- });
142
- return ref.current;
143
- }
144
- function useStateRef(initialValue) {
145
- const [state, setState] = useState(initialValue ?? null);
146
- const ref = useRef(state);
147
- useEffect(() => {
148
- ref.current = state;
149
- }, [state]);
150
- return [state, setState, ref];
151
- }
152
71
  var fixedForwardRef = forwardRef;
153
72
  var FaasDataWrapper = fixedForwardRef(
154
73
  (props, ref) => {
@@ -340,6 +259,14 @@ function getClient(host) {
340
259
  }
341
260
  return client;
342
261
  }
262
+ function useConstant(fn) {
263
+ const ref = useRef(null);
264
+ if (!ref.current) {
265
+ ref.current = { v: fn() };
266
+ }
267
+ return ref.current.v;
268
+ }
269
+ useConstant.whyDidYouRender = true;
343
270
  var ErrorBoundary = class extends Component {
344
271
  static displayName = "ErrorBoundary";
345
272
  static whyDidYouRender = true;
@@ -377,11 +304,73 @@ var ErrorBoundary = class extends Component {
377
304
  return this.props.children;
378
305
  }
379
306
  };
380
- var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
381
- return condition ? /* @__PURE__ */ jsx(Wrapper, { ...wrapperProps, children }) : /* @__PURE__ */ jsx(Fragment, { children });
382
- };
383
- OptionalWrapper.displayName = "OptionalWrapper";
384
- OptionalWrapper.whyDidYouRender = true;
307
+ function useStateRef(initialValue) {
308
+ const [state, setState] = useState(initialValue ?? null);
309
+ const ref = useRef(state);
310
+ useEffect(() => {
311
+ ref.current = state;
312
+ }, [state]);
313
+ return [state, setState, ref];
314
+ }
315
+ function useSplittingState(initialStates) {
316
+ const states = {};
317
+ for (const key of Object.keys(initialStates)) {
318
+ const state = useState(initialStates[key]);
319
+ Object.assign(states, {
320
+ [key]: state[0],
321
+ [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
322
+ });
323
+ }
324
+ return states;
325
+ }
326
+ function createSplittingContext(defaultValue) {
327
+ const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
328
+ const defaultValues = Array.isArray(defaultValue) ? keys.reduce(
329
+ (prev, cur) => {
330
+ prev[cur] = null;
331
+ return prev;
332
+ },
333
+ {}
334
+ ) : defaultValue;
335
+ const contexts = {};
336
+ for (const key of keys) contexts[key] = createContext(defaultValues[key]);
337
+ function Provider(props) {
338
+ const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
339
+ let children = props.memo ? useEqualMemo(
340
+ () => props.children,
341
+ props.memo === true ? [] : props.memo
342
+ ) : props.children;
343
+ for (const key of keys) {
344
+ const Context = contexts[key];
345
+ const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
346
+ children = /* @__PURE__ */ jsx(Context.Provider, { value, children });
347
+ }
348
+ return children;
349
+ }
350
+ Provider.displayName = "SplittingContextProvider";
351
+ Provider.whyDidYouRender = true;
352
+ function use() {
353
+ return useConstant(() => {
354
+ const obj = /* @__PURE__ */ Object.create(null);
355
+ for (const key of Object.keys(contexts)) {
356
+ Object.defineProperty(obj, key, {
357
+ get: () => {
358
+ if (!contexts[key]) {
359
+ throw new Error(`Context for key "${key}" is undefined`);
360
+ }
361
+ return useContext(contexts[key]);
362
+ }
363
+ });
364
+ }
365
+ return Object.freeze(obj);
366
+ });
367
+ }
368
+ use.whyDidYouRender = true;
369
+ return {
370
+ Provider,
371
+ use
372
+ };
373
+ }
385
374
 
386
375
  // src/Form/context.tsx
387
376
  var FormContext = createSplittingContext([
@@ -459,6 +448,45 @@ function FormBody() {
459
448
  }
460
449
  FormBody.displayName = "FormBody";
461
450
  FormBody.whyDidYouRender = true;
451
+ var FormButtonElement = forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsx(
452
+ "button",
453
+ {
454
+ type: "button",
455
+ disabled: submitting,
456
+ onClick: submit,
457
+ ...props,
458
+ ref,
459
+ children
460
+ }
461
+ ));
462
+ FormButtonElement.displayName = "FormButtonElement";
463
+ Object.assign(FormButtonElement, { whyDidYouRender: true });
464
+ var FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
465
+ FormInputElement.displayName = "FormInputElement";
466
+ Object.assign(FormInputElement, { whyDidYouRender: true });
467
+ var FormLabelElement = ({
468
+ name,
469
+ title,
470
+ description,
471
+ error,
472
+ children
473
+ }) => {
474
+ return /* @__PURE__ */ jsxs("label", { children: [
475
+ title ?? name,
476
+ children,
477
+ description,
478
+ error && /* @__PURE__ */ jsx("div", { style: { color: "red" }, children: error.message })
479
+ ] });
480
+ };
481
+ FormLabelElement.displayName = "FormLabelElement";
482
+ FormLabelElement.whyDidYouRender = true;
483
+
484
+ // src/Form/elements/index.ts
485
+ var FormDefaultElements = {
486
+ Label: FormLabelElement,
487
+ Input: FormInputElement,
488
+ Button: FormButtonElement
489
+ };
462
490
 
463
491
  // src/Form/rules.ts
464
492
  var FormDefaultRules = {
@@ -530,45 +558,6 @@ function FormFooter() {
530
558
  }
531
559
  FormFooter.displayName = "FormFooter";
532
560
  FormFooter.whyDidYouRender = true;
533
- var FormButtonElement = forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsx(
534
- "button",
535
- {
536
- type: "button",
537
- disabled: submitting,
538
- onClick: submit,
539
- ...props,
540
- ref,
541
- children
542
- }
543
- ));
544
- FormButtonElement.displayName = "FormButtonElement";
545
- Object.assign(FormButtonElement, { whyDidYouRender: true });
546
- var FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
547
- FormInputElement.displayName = "FormInputElement";
548
- Object.assign(FormInputElement, { whyDidYouRender: true });
549
- var FormLabelElement = ({
550
- name,
551
- title,
552
- description,
553
- error,
554
- children
555
- }) => {
556
- return /* @__PURE__ */ jsxs("label", { children: [
557
- title ?? name,
558
- children,
559
- description,
560
- error && /* @__PURE__ */ jsx("div", { style: { color: "red" }, children: error.message })
561
- ] });
562
- };
563
- FormLabelElement.displayName = "FormLabelElement";
564
- FormLabelElement.whyDidYouRender = true;
565
-
566
- // src/Form/elements/index.ts
567
- var FormDefaultElements = {
568
- Label: FormLabelElement,
569
- Input: FormInputElement,
570
- Button: FormButtonElement
571
- };
572
561
 
573
562
  // src/Form/lang.ts
574
563
  var FormDefaultLang = {
@@ -621,5 +610,17 @@ function FormContainer({
621
610
  }
622
611
  FormContainer.displayName = "FormContainer";
623
612
  FormContainer.whyDidYouRender = true;
613
+ var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
614
+ return condition ? /* @__PURE__ */ jsx(Wrapper, { ...wrapperProps, children }) : /* @__PURE__ */ jsx(Fragment, { children });
615
+ };
616
+ OptionalWrapper.displayName = "OptionalWrapper";
617
+ OptionalWrapper.whyDidYouRender = true;
618
+ function usePrevious(value) {
619
+ const ref = useRef(void 0);
620
+ useEffect(() => {
621
+ ref.current = value;
622
+ });
623
+ return ref.current;
624
+ }
624
625
 
625
626
  export { ErrorBoundary, FaasDataWrapper, FaasReactClient, FormContainer as Form, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormItem, OptionalWrapper, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faasjs/react",
3
- "version": "7.0.0",
3
+ "version": "7.0.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -30,15 +30,15 @@
30
30
  "dist"
31
31
  ],
32
32
  "peerDependencies": {
33
- "@faasjs/browser": ">=7.0.0"
33
+ "@faasjs/browser": ">=7.0.2"
34
34
  },
35
35
  "devDependencies": {
36
- "@faasjs/browser": ">=7.0.0",
36
+ "@faasjs/browser": ">=7.0.2",
37
37
  "@types/react": "*",
38
38
  "react": "*"
39
39
  },
40
40
  "engines": {
41
- "node": ">=22.0.0",
41
+ "node": ">=24.0.0",
42
42
  "npm": ">=11.0.0"
43
43
  }
44
44
  }