@faasjs/react 3.6.1 → 3.7.0-beta.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
@@ -44,6 +44,8 @@ npm install @faasjs/react
44
44
  - [faas](functions/faas.md)
45
45
  - [FaasDataWrapper](functions/FaasDataWrapper.md)
46
46
  - [FaasReactClient](functions/FaasReactClient.md)
47
+ - [Form](functions/Form.md)
48
+ - [FormContextProvider](functions/FormContextProvider.md)
47
49
  - [getClient](functions/getClient.md)
48
50
  - [OptionalWrapper](functions/OptionalWrapper.md)
49
51
  - [useConstant](functions/useConstant.md)
@@ -52,6 +54,7 @@ npm install @faasjs/react
52
54
  - [useEqualMemo](functions/useEqualMemo.md)
53
55
  - [useEqualMemoize](functions/useEqualMemoize.md)
54
56
  - [useFaas](functions/useFaas.md)
57
+ - [useFormContext](functions/useFormContext.md)
55
58
  - [useSplittingState](functions/useSplittingState.md)
56
59
  - [withFaasData](functions/withFaasData.md)
57
60
 
@@ -75,8 +78,15 @@ npm install @faasjs/react
75
78
  - [FaasParams](type-aliases/FaasParams.md)
76
79
  - [FaasReactClientInstance](type-aliases/FaasReactClientInstance.md)
77
80
  - [FaasReactClientOptions](type-aliases/FaasReactClientOptions.md)
81
+ - [FormContextProps](type-aliases/FormContextProps.md)
82
+ - [FormElementTypes](type-aliases/FormElementTypes.md)
83
+ - [FormProps](type-aliases/FormProps.md)
78
84
  - [OnError](type-aliases/OnError.md)
79
85
  - [OptionalWrapperProps](type-aliases/OptionalWrapperProps.md)
80
86
  - [Options](type-aliases/Options.md)
81
87
  - [ResponseHeaders](type-aliases/ResponseHeaders.md)
82
88
  - [useFaasOptions](type-aliases/useFaasOptions.md)
89
+
90
+ ## Variables
91
+
92
+ - [FormDefaultElements](variables/FormDefaultElements.md)
package/dist/index.d.mts CHANGED
@@ -2,6 +2,7 @@ import { FaasAction, FaasData, FaasParams } from '@faasjs/types';
2
2
  export { FaasAction, FaasData, FaasParams } from '@faasjs/types';
3
3
  import { Response, BaseUrl, ResponseError, Options, FaasBrowserClient } from '@faasjs/browser';
4
4
  export { Options, Response, ResponseError, ResponseHeaders } from '@faasjs/browser';
5
+ import * as react from 'react';
5
6
  import { ReactNode, Dispatch, SetStateAction, ReactElement, Component, ComponentType, ComponentProps } from 'react';
6
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
8
 
@@ -371,4 +372,64 @@ declare const OptionalWrapper: React.FC<OptionalWrapperProps> & {
371
372
  whyDidYouRender: boolean;
372
373
  };
373
374
 
374
- export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useSplittingState, withFaasData };
375
+ type FormRules = {
376
+ type?: 'string' | 'number';
377
+ required?: boolean;
378
+ };
379
+
380
+ type FormInputElementProps = {
381
+ name: string;
382
+ value: any;
383
+ onChange: (value: any) => void;
384
+ };
385
+
386
+ type FormLabelElementProps = {
387
+ name: string;
388
+ rules?: FormRules;
389
+ title?: ReactNode;
390
+ description?: ReactNode;
391
+ Label?: React.ComponentType<FormLabelElementProps>;
392
+ input?: {
393
+ Input?: ComponentType<FormInputElementProps>;
394
+ props?: FormInputElementProps;
395
+ };
396
+ };
397
+
398
+ type FormButtonElementProps = {
399
+ children?: React.ReactNode;
400
+ disabled?: boolean;
401
+ onClick?: () => void;
402
+ };
403
+
404
+ type FormElementTypes = {
405
+ Label: ComponentType<FormLabelElementProps>;
406
+ Input: ComponentType<FormInputElementProps>;
407
+ Button: ComponentType<FormButtonElementProps>;
408
+ };
409
+ declare const FormDefaultElements: FormElementTypes;
410
+
411
+ type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes> = {
412
+ items: FormLabelElementProps[];
413
+ onSubmit?: (values: Values) => Promise<void>;
414
+ elements?: FormElements;
415
+ defaultValues?: Values;
416
+ };
417
+ declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes>({ defaultValues, elements, ...props }: FormProps<Values, FormElements>): react_jsx_runtime.JSX.Element;
418
+
419
+ type FormContextProps<Values extends Record<string, any> = Record<string, any>> = {
420
+ items: FormLabelElementProps[];
421
+ onSubmit: (values: Values) => Promise<void>;
422
+ Elements: FormElementTypes;
423
+ submitting: boolean;
424
+ setSubmitting: React.Dispatch<React.SetStateAction<boolean>>;
425
+ values: Values;
426
+ setValues: React.Dispatch<React.SetStateAction<Values>>;
427
+ };
428
+ declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>> = FormContextProps<Record<string, any>>>(props: {
429
+ value?: NewT;
430
+ children: react.ReactNode;
431
+ memo?: true | any[];
432
+ }) => react.ReactNode;
433
+ declare const useFormContext: <NewT extends FormContextProps<Record<string, any>> = FormContextProps<Record<string, any>>>() => Readonly<NewT>;
434
+
435
+ export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, FormContainer as Form, type FormContextProps, FormContextProvider, FormDefaultElements, type FormElementTypes, type FormProps, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useFormContext, useSplittingState, withFaasData };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { FaasAction, FaasData, FaasParams } from '@faasjs/types';
2
2
  export { FaasAction, FaasData, FaasParams } from '@faasjs/types';
3
3
  import { Response, BaseUrl, ResponseError, Options, FaasBrowserClient } from '@faasjs/browser';
4
4
  export { Options, Response, ResponseError, ResponseHeaders } from '@faasjs/browser';
5
+ import * as react from 'react';
5
6
  import { ReactNode, Dispatch, SetStateAction, ReactElement, Component, ComponentType, ComponentProps } from 'react';
6
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
8
 
@@ -371,4 +372,64 @@ declare const OptionalWrapper: React.FC<OptionalWrapperProps> & {
371
372
  whyDidYouRender: boolean;
372
373
  };
373
374
 
374
- export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useSplittingState, withFaasData };
375
+ type FormRules = {
376
+ type?: 'string' | 'number';
377
+ required?: boolean;
378
+ };
379
+
380
+ type FormInputElementProps = {
381
+ name: string;
382
+ value: any;
383
+ onChange: (value: any) => void;
384
+ };
385
+
386
+ type FormLabelElementProps = {
387
+ name: string;
388
+ rules?: FormRules;
389
+ title?: ReactNode;
390
+ description?: ReactNode;
391
+ Label?: React.ComponentType<FormLabelElementProps>;
392
+ input?: {
393
+ Input?: ComponentType<FormInputElementProps>;
394
+ props?: FormInputElementProps;
395
+ };
396
+ };
397
+
398
+ type FormButtonElementProps = {
399
+ children?: React.ReactNode;
400
+ disabled?: boolean;
401
+ onClick?: () => void;
402
+ };
403
+
404
+ type FormElementTypes = {
405
+ Label: ComponentType<FormLabelElementProps>;
406
+ Input: ComponentType<FormInputElementProps>;
407
+ Button: ComponentType<FormButtonElementProps>;
408
+ };
409
+ declare const FormDefaultElements: FormElementTypes;
410
+
411
+ type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes> = {
412
+ items: FormLabelElementProps[];
413
+ onSubmit?: (values: Values) => Promise<void>;
414
+ elements?: FormElements;
415
+ defaultValues?: Values;
416
+ };
417
+ declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes>({ defaultValues, elements, ...props }: FormProps<Values, FormElements>): react_jsx_runtime.JSX.Element;
418
+
419
+ type FormContextProps<Values extends Record<string, any> = Record<string, any>> = {
420
+ items: FormLabelElementProps[];
421
+ onSubmit: (values: Values) => Promise<void>;
422
+ Elements: FormElementTypes;
423
+ submitting: boolean;
424
+ setSubmitting: React.Dispatch<React.SetStateAction<boolean>>;
425
+ values: Values;
426
+ setValues: React.Dispatch<React.SetStateAction<Values>>;
427
+ };
428
+ declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>> = FormContextProps<Record<string, any>>>(props: {
429
+ value?: NewT;
430
+ children: react.ReactNode;
431
+ memo?: true | any[];
432
+ }) => react.ReactNode;
433
+ declare const useFormContext: <NewT extends FormContextProps<Record<string, any>> = FormContextProps<Record<string, any>>>() => Readonly<NewT>;
434
+
435
+ export { ErrorBoundary, type ErrorBoundaryProps, type ErrorChildrenProps, type FaasDataInjection, FaasDataWrapper, type FaasDataWrapperProps, FaasReactClient, type FaasReactClientInstance, type FaasReactClientOptions, FormContainer as Form, type FormContextProps, FormContextProvider, FormDefaultElements, type FormElementTypes, type FormProps, type OnError, OptionalWrapper, type OptionalWrapperProps, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, type useFaasOptions, useFormContext, useSplittingState, withFaasData };
package/dist/index.js CHANGED
@@ -334,9 +334,120 @@ var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
334
334
  };
335
335
  OptionalWrapper.whyDidYouRender = true;
336
336
 
337
+ // src/Form/context.tsx
338
+ var FormContext = createSplittingContext(["items", "onSubmit", "Elements", "submitting", "setSubmitting", "values", "setValues"]);
339
+ var FormContextProvider = FormContext.Provider;
340
+ var useFormContext = FormContext.use;
341
+ function FormLabel(props) {
342
+ const { Elements } = useFormContext();
343
+ if (props.Label) return /* @__PURE__ */ jsxRuntime.jsx(props.Label, { ...props });
344
+ return /* @__PURE__ */ jsxRuntime.jsx(Elements.Label, { ...props });
345
+ }
346
+ function FormBody() {
347
+ const { items } = useFormContext();
348
+ return items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(FormLabel, { ...item }, item.name));
349
+ }
350
+ var FormInputElement = react.forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
351
+ var FormLabelElement = ({
352
+ name,
353
+ title,
354
+ description,
355
+ Label,
356
+ input
357
+ }) => {
358
+ const { values, setValues } = useFormContext();
359
+ if (Label) return /* @__PURE__ */ jsxRuntime.jsx(Label, { name, title, description, input });
360
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
361
+ title ?? name,
362
+ input?.Input ? /* @__PURE__ */ jsxRuntime.jsx(
363
+ input.Input,
364
+ {
365
+ name,
366
+ value: values[name],
367
+ onChange: (v) => setValues((prev) => ({
368
+ ...prev,
369
+ [name]: v
370
+ }))
371
+ }
372
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
373
+ FormInputElement,
374
+ {
375
+ name,
376
+ value: values[name],
377
+ onChange: (v) => setValues((prev) => ({
378
+ ...prev,
379
+ [name]: v
380
+ }))
381
+ }
382
+ ),
383
+ description
384
+ ] });
385
+ };
386
+ var FormButtonElement = react.forwardRef(({ disabled, children, onClick, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
387
+ "button",
388
+ {
389
+ type: "button",
390
+ disabled,
391
+ onClick,
392
+ ...props,
393
+ ref,
394
+ children
395
+ }
396
+ ));
397
+
398
+ // src/Form/elements/index.ts
399
+ var FormDefaultElements = {
400
+ Label: FormLabelElement,
401
+ Input: FormInputElement,
402
+ Button: FormButtonElement
403
+ };
404
+ function FormFooter() {
405
+ const { submitting, setSubmitting, onSubmit, values, Elements } = useFormContext();
406
+ return /* @__PURE__ */ jsxRuntime.jsx(
407
+ Elements.Button,
408
+ {
409
+ disabled: submitting,
410
+ onClick: () => {
411
+ setSubmitting(true);
412
+ onSubmit(values).finally(() => setSubmitting(false));
413
+ },
414
+ children: "Submit"
415
+ }
416
+ );
417
+ }
418
+ function mergeValues(items, defaultValues = {}) {
419
+ const values = {};
420
+ for (const item of items)
421
+ values[item.name] = defaultValues[item.name] ?? "";
422
+ return values;
423
+ }
424
+ function FormContainer({ defaultValues, elements, ...props }) {
425
+ const states = useSplittingState({
426
+ values: mergeValues(props.items, defaultValues),
427
+ submitting: false,
428
+ Elements: Object.assign(FormDefaultElements, elements)
429
+ });
430
+ return /* @__PURE__ */ jsxRuntime.jsxs(
431
+ FormContextProvider,
432
+ {
433
+ value: {
434
+ ...states,
435
+ ...props
436
+ },
437
+ children: [
438
+ /* @__PURE__ */ jsxRuntime.jsx(FormBody, {}),
439
+ /* @__PURE__ */ jsxRuntime.jsx(FormFooter, {})
440
+ ]
441
+ }
442
+ );
443
+ }
444
+
337
445
  exports.ErrorBoundary = ErrorBoundary;
338
446
  exports.FaasDataWrapper = FaasDataWrapper;
339
447
  exports.FaasReactClient = FaasReactClient;
448
+ exports.Form = FormContainer;
449
+ exports.FormContextProvider = FormContextProvider;
450
+ exports.FormDefaultElements = FormDefaultElements;
340
451
  exports.OptionalWrapper = OptionalWrapper;
341
452
  exports.createSplittingContext = createSplittingContext;
342
453
  exports.equal = equal;
@@ -348,5 +459,6 @@ exports.useEqualEffect = useEqualEffect;
348
459
  exports.useEqualMemo = useEqualMemo;
349
460
  exports.useEqualMemoize = useEqualMemoize;
350
461
  exports.useFaas = useFaas;
462
+ exports.useFormContext = useFormContext;
351
463
  exports.useSplittingState = useSplittingState;
352
464
  exports.withFaasData = withFaasData;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { useRef, useMemo, useEffect, useCallback, createContext, useState, cloneElement, Component, useContext } from 'react';
1
+ import { forwardRef, useRef, useMemo, useEffect, useCallback, createContext, useState, cloneElement, Component, useContext } from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { FaasBrowserClient } from '@faasjs/browser';
4
4
 
@@ -332,4 +332,112 @@ var OptionalWrapper = ({ condition, Wrapper, wrapperProps, children }) => {
332
332
  };
333
333
  OptionalWrapper.whyDidYouRender = true;
334
334
 
335
- export { ErrorBoundary, FaasDataWrapper, FaasReactClient, OptionalWrapper, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useSplittingState, withFaasData };
335
+ // src/Form/context.tsx
336
+ var FormContext = createSplittingContext(["items", "onSubmit", "Elements", "submitting", "setSubmitting", "values", "setValues"]);
337
+ var FormContextProvider = FormContext.Provider;
338
+ var useFormContext = FormContext.use;
339
+ function FormLabel(props) {
340
+ const { Elements } = useFormContext();
341
+ if (props.Label) return /* @__PURE__ */ jsx(props.Label, { ...props });
342
+ return /* @__PURE__ */ jsx(Elements.Label, { ...props });
343
+ }
344
+ function FormBody() {
345
+ const { items } = useFormContext();
346
+ return items.map((item) => /* @__PURE__ */ jsx(FormLabel, { ...item }, item.name));
347
+ }
348
+ var FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", { ...props, onChange: (e) => onChange(e.target.value), ref }));
349
+ var FormLabelElement = ({
350
+ name,
351
+ title,
352
+ description,
353
+ Label,
354
+ input
355
+ }) => {
356
+ const { values, setValues } = useFormContext();
357
+ if (Label) return /* @__PURE__ */ jsx(Label, { name, title, description, input });
358
+ return /* @__PURE__ */ jsxs("label", { children: [
359
+ title ?? name,
360
+ input?.Input ? /* @__PURE__ */ jsx(
361
+ input.Input,
362
+ {
363
+ name,
364
+ value: values[name],
365
+ onChange: (v) => setValues((prev) => ({
366
+ ...prev,
367
+ [name]: v
368
+ }))
369
+ }
370
+ ) : /* @__PURE__ */ jsx(
371
+ FormInputElement,
372
+ {
373
+ name,
374
+ value: values[name],
375
+ onChange: (v) => setValues((prev) => ({
376
+ ...prev,
377
+ [name]: v
378
+ }))
379
+ }
380
+ ),
381
+ description
382
+ ] });
383
+ };
384
+ var FormButtonElement = forwardRef(({ disabled, children, onClick, ...props }, ref) => /* @__PURE__ */ jsx(
385
+ "button",
386
+ {
387
+ type: "button",
388
+ disabled,
389
+ onClick,
390
+ ...props,
391
+ ref,
392
+ children
393
+ }
394
+ ));
395
+
396
+ // src/Form/elements/index.ts
397
+ var FormDefaultElements = {
398
+ Label: FormLabelElement,
399
+ Input: FormInputElement,
400
+ Button: FormButtonElement
401
+ };
402
+ function FormFooter() {
403
+ const { submitting, setSubmitting, onSubmit, values, Elements } = useFormContext();
404
+ return /* @__PURE__ */ jsx(
405
+ Elements.Button,
406
+ {
407
+ disabled: submitting,
408
+ onClick: () => {
409
+ setSubmitting(true);
410
+ onSubmit(values).finally(() => setSubmitting(false));
411
+ },
412
+ children: "Submit"
413
+ }
414
+ );
415
+ }
416
+ function mergeValues(items, defaultValues = {}) {
417
+ const values = {};
418
+ for (const item of items)
419
+ values[item.name] = defaultValues[item.name] ?? "";
420
+ return values;
421
+ }
422
+ function FormContainer({ defaultValues, elements, ...props }) {
423
+ const states = useSplittingState({
424
+ values: mergeValues(props.items, defaultValues),
425
+ submitting: false,
426
+ Elements: Object.assign(FormDefaultElements, elements)
427
+ });
428
+ return /* @__PURE__ */ jsxs(
429
+ FormContextProvider,
430
+ {
431
+ value: {
432
+ ...states,
433
+ ...props
434
+ },
435
+ children: [
436
+ /* @__PURE__ */ jsx(FormBody, {}),
437
+ /* @__PURE__ */ jsx(FormFooter, {})
438
+ ]
439
+ }
440
+ );
441
+ }
442
+
443
+ export { ErrorBoundary, FaasDataWrapper, FaasReactClient, FormContainer as Form, FormContextProvider, FormDefaultElements, OptionalWrapper, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFormContext, useSplittingState, withFaasData };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faasjs/react",
3
- "version": "3.6.1",
3
+ "version": "3.7.0-beta.1",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -28,19 +28,18 @@
28
28
  },
29
29
  "funding": "https://github.com/sponsors/faasjs",
30
30
  "scripts": {
31
- "build": "tsup src/index.tsx --config ../../tsup.config.json"
31
+ "build": "tsup src/index.tsx --config ../../tsup.config.json --external react"
32
32
  },
33
33
  "files": [
34
34
  "dist"
35
35
  ],
36
36
  "peerDependencies": {
37
- "react": "*",
38
- "@faasjs/browser": "3.6.1"
37
+ "@faasjs/browser": "3.7.0-beta.1"
39
38
  },
40
39
  "devDependencies": {
40
+ "@faasjs/browser": "3.7.0-beta.1",
41
41
  "@types/react": "*",
42
- "react": "*",
43
- "@faasjs/browser": "3.6.1"
42
+ "react": "*"
44
43
  },
45
44
  "engines": {
46
45
  "node": ">=22.0.0",