@faasjs/react 7.0.0-beta.2 → 7.0.1

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) {
@@ -77,80 +69,6 @@ function useEqualCallback(callback, dependencies) {
77
69
  useEqualMemoize(dependencies)
78
70
  );
79
71
  }
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
72
  var fixedForwardRef = react.forwardRef;
155
73
  var FaasDataWrapper = fixedForwardRef(
156
74
  (props, ref) => {
@@ -342,6 +260,14 @@ function getClient(host) {
342
260
  }
343
261
  return client;
344
262
  }
263
+ function useConstant(fn) {
264
+ const ref = react.useRef(null);
265
+ if (!ref.current) {
266
+ ref.current = { v: fn() };
267
+ }
268
+ return ref.current.v;
269
+ }
270
+ useConstant.whyDidYouRender = true;
345
271
  var ErrorBoundary = class extends react.Component {
346
272
  static displayName = "ErrorBoundary";
347
273
  static whyDidYouRender = true;
@@ -379,11 +305,73 @@ var ErrorBoundary = class extends react.Component {
379
305
  return this.props.children;
380
306
  }
381
307
  };
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;
308
+ function useStateRef(initialValue) {
309
+ const [state, setState] = react.useState(initialValue ?? null);
310
+ const ref = react.useRef(state);
311
+ react.useEffect(() => {
312
+ ref.current = state;
313
+ }, [state]);
314
+ return [state, setState, ref];
315
+ }
316
+ function useSplittingState(initialStates) {
317
+ const states = {};
318
+ for (const key of Object.keys(initialStates)) {
319
+ const state = react.useState(initialStates[key]);
320
+ Object.assign(states, {
321
+ [key]: state[0],
322
+ [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
323
+ });
324
+ }
325
+ return states;
326
+ }
327
+ function createSplittingContext(defaultValue) {
328
+ const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
329
+ const defaultValues = Array.isArray(defaultValue) ? keys.reduce(
330
+ (prev, cur) => {
331
+ prev[cur] = null;
332
+ return prev;
333
+ },
334
+ {}
335
+ ) : defaultValue;
336
+ const contexts = {};
337
+ for (const key of keys) contexts[key] = react.createContext(defaultValues[key]);
338
+ function Provider(props) {
339
+ const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
340
+ let children = props.memo ? useEqualMemo(
341
+ () => props.children,
342
+ props.memo === true ? [] : props.memo
343
+ ) : props.children;
344
+ for (const key of keys) {
345
+ const Context = contexts[key];
346
+ const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
347
+ children = /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
348
+ }
349
+ return children;
350
+ }
351
+ Provider.displayName = "SplittingContextProvider";
352
+ Provider.whyDidYouRender = true;
353
+ function use() {
354
+ return useConstant(() => {
355
+ const obj = /* @__PURE__ */ Object.create(null);
356
+ for (const key of Object.keys(contexts)) {
357
+ Object.defineProperty(obj, key, {
358
+ get: () => {
359
+ if (!contexts[key]) {
360
+ throw new Error(`Context for key "${key}" is undefined`);
361
+ }
362
+ return react.useContext(contexts[key]);
363
+ }
364
+ });
365
+ }
366
+ return Object.freeze(obj);
367
+ });
368
+ }
369
+ use.whyDidYouRender = true;
370
+ return {
371
+ Provider,
372
+ use
373
+ };
374
+ }
387
375
 
388
376
  // src/Form/context.tsx
389
377
  var FormContext = createSplittingContext([
@@ -461,6 +449,45 @@ function FormBody() {
461
449
  }
462
450
  FormBody.displayName = "FormBody";
463
451
  FormBody.whyDidYouRender = true;
452
+ var FormButtonElement = react.forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
453
+ "button",
454
+ {
455
+ type: "button",
456
+ disabled: submitting,
457
+ onClick: submit,
458
+ ...props,
459
+ ref,
460
+ children
461
+ }
462
+ ));
463
+ FormButtonElement.displayName = "FormButtonElement";
464
+ Object.assign(FormButtonElement, { whyDidYouRender: true });
465
+ var FormInputElement = react.forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
466
+ FormInputElement.displayName = "FormInputElement";
467
+ Object.assign(FormInputElement, { whyDidYouRender: true });
468
+ var FormLabelElement = ({
469
+ name,
470
+ title,
471
+ description,
472
+ error,
473
+ children
474
+ }) => {
475
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
476
+ title ?? name,
477
+ children,
478
+ description,
479
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "red" }, children: error.message })
480
+ ] });
481
+ };
482
+ FormLabelElement.displayName = "FormLabelElement";
483
+ FormLabelElement.whyDidYouRender = true;
484
+
485
+ // src/Form/elements/index.ts
486
+ var FormDefaultElements = {
487
+ Label: FormLabelElement,
488
+ Input: FormInputElement,
489
+ Button: FormButtonElement
490
+ };
464
491
 
465
492
  // src/Form/rules.ts
466
493
  var FormDefaultRules = {
@@ -532,45 +559,6 @@ function FormFooter() {
532
559
  }
533
560
  FormFooter.displayName = "FormFooter";
534
561
  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
562
 
575
563
  // src/Form/lang.ts
576
564
  var FormDefaultLang = {
@@ -623,6 +611,18 @@ function FormContainer({
623
611
  }
624
612
  FormContainer.displayName = "FormContainer";
625
613
  FormContainer.whyDidYouRender = true;
614
+ var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
615
+ return condition ? /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { ...wrapperProps, children }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
616
+ };
617
+ OptionalWrapper.displayName = "OptionalWrapper";
618
+ OptionalWrapper.whyDidYouRender = true;
619
+ function usePrevious(value) {
620
+ const ref = react.useRef(void 0);
621
+ react.useEffect(() => {
622
+ ref.current = value;
623
+ });
624
+ return ref.current;
625
+ }
626
626
 
627
627
  exports.ErrorBoundary = ErrorBoundary;
628
628
  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) {
@@ -75,80 +67,6 @@ function useEqualCallback(callback, dependencies) {
75
67
  useEqualMemoize(dependencies)
76
68
  );
77
69
  }
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
70
  var fixedForwardRef = forwardRef;
153
71
  var FaasDataWrapper = fixedForwardRef(
154
72
  (props, ref) => {
@@ -340,6 +258,14 @@ function getClient(host) {
340
258
  }
341
259
  return client;
342
260
  }
261
+ function useConstant(fn) {
262
+ const ref = useRef(null);
263
+ if (!ref.current) {
264
+ ref.current = { v: fn() };
265
+ }
266
+ return ref.current.v;
267
+ }
268
+ useConstant.whyDidYouRender = true;
343
269
  var ErrorBoundary = class extends Component {
344
270
  static displayName = "ErrorBoundary";
345
271
  static whyDidYouRender = true;
@@ -377,11 +303,73 @@ var ErrorBoundary = class extends Component {
377
303
  return this.props.children;
378
304
  }
379
305
  };
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;
306
+ function useStateRef(initialValue) {
307
+ const [state, setState] = useState(initialValue ?? null);
308
+ const ref = useRef(state);
309
+ useEffect(() => {
310
+ ref.current = state;
311
+ }, [state]);
312
+ return [state, setState, ref];
313
+ }
314
+ function useSplittingState(initialStates) {
315
+ const states = {};
316
+ for (const key of Object.keys(initialStates)) {
317
+ const state = useState(initialStates[key]);
318
+ Object.assign(states, {
319
+ [key]: state[0],
320
+ [`set${String(key).charAt(0).toUpperCase()}${String(key).slice(1)}`]: state[1]
321
+ });
322
+ }
323
+ return states;
324
+ }
325
+ function createSplittingContext(defaultValue) {
326
+ const keys = Array.isArray(defaultValue) ? defaultValue : Object.keys(defaultValue);
327
+ const defaultValues = Array.isArray(defaultValue) ? keys.reduce(
328
+ (prev, cur) => {
329
+ prev[cur] = null;
330
+ return prev;
331
+ },
332
+ {}
333
+ ) : defaultValue;
334
+ const contexts = {};
335
+ for (const key of keys) contexts[key] = createContext(defaultValues[key]);
336
+ function Provider(props) {
337
+ const states = props.initializeStates ? useSplittingState(props.initializeStates) : {};
338
+ let children = props.memo ? useEqualMemo(
339
+ () => props.children,
340
+ props.memo === true ? [] : props.memo
341
+ ) : props.children;
342
+ for (const key of keys) {
343
+ const Context = contexts[key];
344
+ const value = props.value?.[key] ?? states[key] ?? defaultValues[key];
345
+ children = /* @__PURE__ */ jsx(Context.Provider, { value, children });
346
+ }
347
+ return children;
348
+ }
349
+ Provider.displayName = "SplittingContextProvider";
350
+ Provider.whyDidYouRender = true;
351
+ function use() {
352
+ return useConstant(() => {
353
+ const obj = /* @__PURE__ */ Object.create(null);
354
+ for (const key of Object.keys(contexts)) {
355
+ Object.defineProperty(obj, key, {
356
+ get: () => {
357
+ if (!contexts[key]) {
358
+ throw new Error(`Context for key "${key}" is undefined`);
359
+ }
360
+ return useContext(contexts[key]);
361
+ }
362
+ });
363
+ }
364
+ return Object.freeze(obj);
365
+ });
366
+ }
367
+ use.whyDidYouRender = true;
368
+ return {
369
+ Provider,
370
+ use
371
+ };
372
+ }
385
373
 
386
374
  // src/Form/context.tsx
387
375
  var FormContext = createSplittingContext([
@@ -459,6 +447,45 @@ function FormBody() {
459
447
  }
460
448
  FormBody.displayName = "FormBody";
461
449
  FormBody.whyDidYouRender = true;
450
+ var FormButtonElement = forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsx(
451
+ "button",
452
+ {
453
+ type: "button",
454
+ disabled: submitting,
455
+ onClick: submit,
456
+ ...props,
457
+ ref,
458
+ children
459
+ }
460
+ ));
461
+ FormButtonElement.displayName = "FormButtonElement";
462
+ Object.assign(FormButtonElement, { whyDidYouRender: true });
463
+ var FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
464
+ FormInputElement.displayName = "FormInputElement";
465
+ Object.assign(FormInputElement, { whyDidYouRender: true });
466
+ var FormLabelElement = ({
467
+ name,
468
+ title,
469
+ description,
470
+ error,
471
+ children
472
+ }) => {
473
+ return /* @__PURE__ */ jsxs("label", { children: [
474
+ title ?? name,
475
+ children,
476
+ description,
477
+ error && /* @__PURE__ */ jsx("div", { style: { color: "red" }, children: error.message })
478
+ ] });
479
+ };
480
+ FormLabelElement.displayName = "FormLabelElement";
481
+ FormLabelElement.whyDidYouRender = true;
482
+
483
+ // src/Form/elements/index.ts
484
+ var FormDefaultElements = {
485
+ Label: FormLabelElement,
486
+ Input: FormInputElement,
487
+ Button: FormButtonElement
488
+ };
462
489
 
463
490
  // src/Form/rules.ts
464
491
  var FormDefaultRules = {
@@ -530,45 +557,6 @@ function FormFooter() {
530
557
  }
531
558
  FormFooter.displayName = "FormFooter";
532
559
  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
560
 
573
561
  // src/Form/lang.ts
574
562
  var FormDefaultLang = {
@@ -621,5 +609,17 @@ function FormContainer({
621
609
  }
622
610
  FormContainer.displayName = "FormContainer";
623
611
  FormContainer.whyDidYouRender = true;
612
+ var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
613
+ return condition ? /* @__PURE__ */ jsx(Wrapper, { ...wrapperProps, children }) : /* @__PURE__ */ jsx(Fragment, { children });
614
+ };
615
+ OptionalWrapper.displayName = "OptionalWrapper";
616
+ OptionalWrapper.whyDidYouRender = true;
617
+ function usePrevious(value) {
618
+ const ref = useRef(void 0);
619
+ useEffect(() => {
620
+ ref.current = value;
621
+ });
622
+ return ref.current;
623
+ }
624
624
 
625
625
  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-beta.2",
3
+ "version": "7.0.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -30,10 +30,10 @@
30
30
  "dist"
31
31
  ],
32
32
  "peerDependencies": {
33
- "@faasjs/browser": ">=7.0.0-beta.2"
33
+ "@faasjs/browser": ">=7.0.1"
34
34
  },
35
35
  "devDependencies": {
36
- "@faasjs/browser": ">=7.0.0-beta.2",
36
+ "@faasjs/browser": ">=7.0.1",
37
37
  "@types/react": "*",
38
38
  "react": "*"
39
39
  },