@faasjs/react 8.0.0-beta.15 → 8.0.0-beta.17
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 +0 -25
- package/dist/index.cjs +132 -359
- package/dist/index.d.ts +116 -295
- package/dist/index.mjs +133 -351
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -36,9 +36,6 @@ function generateId(prefix = "", length = 18) {
|
|
|
36
36
|
* @property {T} [data] - The parsed JSON data from the response.
|
|
37
37
|
* Optional property that contains the response payload when JSON is provided.
|
|
38
38
|
*
|
|
39
|
-
* @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
|
|
40
|
-
* All properties are optional with sensible defaults.
|
|
41
|
-
*
|
|
42
39
|
* Notes:
|
|
43
40
|
* - status defaults to 200 if data or body is present, 204 otherwise
|
|
44
41
|
* - body is automatically populated from data if not explicitly provided
|
|
@@ -142,6 +139,12 @@ var Response = class {
|
|
|
142
139
|
headers;
|
|
143
140
|
body;
|
|
144
141
|
data;
|
|
142
|
+
/**
|
|
143
|
+
* Create a wrapped response object.
|
|
144
|
+
*
|
|
145
|
+
* @param props - Response properties including status, headers, body, and data.
|
|
146
|
+
* @returns Wrapped response instance.
|
|
147
|
+
*/
|
|
145
148
|
constructor(props = {}) {
|
|
146
149
|
this.status = props.status || (props.data || props.body ? 200 : 204);
|
|
147
150
|
this.headers = props.headers || {};
|
|
@@ -156,7 +159,6 @@ var Response = class {
|
|
|
156
159
|
* Extends the built-in Error class to provide additional information about failed requests,
|
|
157
160
|
* including HTTP status code, response headers, response body, and the original error.
|
|
158
161
|
*
|
|
159
|
-
* @class ResponseError
|
|
160
162
|
* @augments Error
|
|
161
163
|
*
|
|
162
164
|
* @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
|
|
@@ -164,9 +166,6 @@ var Response = class {
|
|
|
164
166
|
* @property {any} body - The response body containing error details or the original error if available.
|
|
165
167
|
* @property {Error} [originalError] - The original Error object if this ResponseError was created from another Error.
|
|
166
168
|
*
|
|
167
|
-
* @param {string | Error | ResponseErrorProps} data - The error message, an Error object, or a ResponseErrorProps object.
|
|
168
|
-
* @param {Omit<ResponseErrorProps, 'message' | 'originalError'>} [options] - Additional options for the error (status, headers, body).
|
|
169
|
-
*
|
|
170
169
|
* @example Basic error with message
|
|
171
170
|
* ```ts
|
|
172
171
|
* throw new ResponseError('User not found')
|
|
@@ -255,6 +254,13 @@ var ResponseError = class extends Error {
|
|
|
255
254
|
headers;
|
|
256
255
|
body;
|
|
257
256
|
originalError;
|
|
257
|
+
/**
|
|
258
|
+
* Create a ResponseError from a message, Error, or structured response error payload.
|
|
259
|
+
*
|
|
260
|
+
* @param data - Error message, Error object, or structured response error props.
|
|
261
|
+
* @param options - Additional options such as status, headers, and body.
|
|
262
|
+
* @returns ResponseError instance.
|
|
263
|
+
*/
|
|
258
264
|
constructor(data, options) {
|
|
259
265
|
let props;
|
|
260
266
|
if (typeof data === "string") props = {
|
|
@@ -406,11 +412,8 @@ var FaasBrowserClient = class {
|
|
|
406
412
|
/**
|
|
407
413
|
* Creates a new FaasBrowserClient instance.
|
|
408
414
|
*
|
|
409
|
-
* @param baseUrl - Base URL for all API requests. Must end with
|
|
410
|
-
*
|
|
411
|
-
* @param options - Configuration options for the client.
|
|
412
|
-
* Supports default headers, beforeRequest hook, custom request function,
|
|
413
|
-
* baseUrl override, and streaming mode.
|
|
415
|
+
* @param baseUrl - Base URL for all API requests. Must end with `/`. Defaults to `/` for relative requests.
|
|
416
|
+
* @param options - Default request options such as headers, hooks, request override, or stream mode.
|
|
414
417
|
*
|
|
415
418
|
* @example Basic initialization
|
|
416
419
|
* ```ts
|
|
@@ -461,7 +464,7 @@ var FaasBrowserClient = class {
|
|
|
461
464
|
* })
|
|
462
465
|
* ```
|
|
463
466
|
*
|
|
464
|
-
* @throws {Error} When baseUrl does not end with
|
|
467
|
+
* @throws {Error} When `baseUrl` does not end with `/`
|
|
465
468
|
*/
|
|
466
469
|
constructor(baseUrl = "/", options = Object.create(null)) {
|
|
467
470
|
if (baseUrl && !baseUrl.endsWith("/")) throw Error("[FaasJS] baseUrl should end with /");
|
|
@@ -486,7 +489,7 @@ var FaasBrowserClient = class {
|
|
|
486
489
|
*
|
|
487
490
|
* @throws {Error} When action is not provided or is empty
|
|
488
491
|
* @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
|
|
489
|
-
* @throws {
|
|
492
|
+
* @throws {Error} When the request fails before a response is received
|
|
490
493
|
*
|
|
491
494
|
* Notes:
|
|
492
495
|
* - All requests are POST requests by default
|
|
@@ -540,11 +543,7 @@ var FaasBrowserClient = class {
|
|
|
540
543
|
* email: string
|
|
541
544
|
* }
|
|
542
545
|
*
|
|
543
|
-
* const response = await client.action<{
|
|
544
|
-
* action: 'user'
|
|
545
|
-
* params: { id: number }
|
|
546
|
-
* data: UserData
|
|
547
|
-
* }>('user', { id: 123 })
|
|
546
|
+
* const response = await client.action<UserData>('user', { id: 123 })
|
|
548
547
|
* console.log(response.data.name) // TypeScript knows it's a string
|
|
549
548
|
* ```
|
|
550
549
|
*
|
|
@@ -556,7 +555,7 @@ var FaasBrowserClient = class {
|
|
|
556
555
|
* } catch (error) {
|
|
557
556
|
* if (error instanceof ResponseError) {
|
|
558
557
|
* console.error(`Server error: ${error.message}`, error.status)
|
|
559
|
-
* if (error.
|
|
558
|
+
* if (error.body) console.error('Error details:', error.body)
|
|
560
559
|
* } else {
|
|
561
560
|
* console.error('Network error:', error)
|
|
562
561
|
* }
|
|
@@ -662,17 +661,20 @@ var FaasBrowserClient = class {
|
|
|
662
661
|
//#endregion
|
|
663
662
|
//#region src/faas.ts
|
|
664
663
|
/**
|
|
665
|
-
*
|
|
664
|
+
* Call the currently configured FaasReactClient.
|
|
666
665
|
*
|
|
667
|
-
* @param action
|
|
668
|
-
* @param params
|
|
669
|
-
* @
|
|
666
|
+
* @param action - Action path to invoke.
|
|
667
|
+
* @param params - Parameters sent to the action.
|
|
668
|
+
* @param options - Optional per-request overrides such as headers or base URL.
|
|
669
|
+
* @returns Response returned by the active browser client.
|
|
670
670
|
*
|
|
671
671
|
* @example
|
|
672
672
|
* ```ts
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
* })
|
|
673
|
+
* import { faas } from '@faasjs/react'
|
|
674
|
+
*
|
|
675
|
+
* const response = await faas<{ title: string }>('post/get', { id: 1 })
|
|
676
|
+
*
|
|
677
|
+
* console.log(response.data.title)
|
|
676
678
|
* ```
|
|
677
679
|
*/
|
|
678
680
|
async function faas(action, params, options) {
|
|
@@ -831,16 +833,23 @@ function withFaasData(Component, faasProps) {
|
|
|
831
833
|
//#endregion
|
|
832
834
|
//#region src/useFaas.tsx
|
|
833
835
|
/**
|
|
834
|
-
* Request
|
|
836
|
+
* Request FaasJS data and keep request state in React state.
|
|
835
837
|
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
838
|
-
*
|
|
838
|
+
* `useFaas` sends an initial request unless `skip` is enabled, and returns
|
|
839
|
+
* request state plus helpers for reloading, updating data, and handling errors.
|
|
840
|
+
*
|
|
841
|
+
* @param action - Action path to invoke.
|
|
842
|
+
* @param defaultParams - Params used for the initial request and future reloads.
|
|
843
|
+
* @param options - Optional hook configuration such as controlled data, debounce, and skip logic.
|
|
844
|
+
* @returns Request state and helper methods for the action.
|
|
839
845
|
*
|
|
840
846
|
* @example
|
|
841
847
|
* ```tsx
|
|
842
|
-
*
|
|
848
|
+
* import { useFaas } from '@faasjs/react'
|
|
849
|
+
*
|
|
850
|
+
* function Post({ id }: { id: number }) {
|
|
843
851
|
* const { data } = useFaas<{ title: string }>('post/get', { id })
|
|
852
|
+
*
|
|
844
853
|
* return <h1>{data.title}</h1>
|
|
845
854
|
* }
|
|
846
855
|
* ```
|
|
@@ -960,14 +969,20 @@ function useFaas(action, defaultParams, options = {}) {
|
|
|
960
969
|
//#region src/client.tsx
|
|
961
970
|
const clients = {};
|
|
962
971
|
/**
|
|
963
|
-
*
|
|
972
|
+
* Create and register a FaasReactClient instance.
|
|
964
973
|
*
|
|
965
|
-
*
|
|
974
|
+
* The returned client is stored by `baseUrl` and becomes the default client
|
|
975
|
+
* used by helpers such as {@link faas} and {@link useFaas}.
|
|
976
|
+
*
|
|
977
|
+
* @param options - Client configuration including base URL, default request options, and error hooks.
|
|
978
|
+
* @returns Registered FaasReactClient instance.
|
|
966
979
|
*
|
|
967
980
|
* @example
|
|
968
981
|
* ```ts
|
|
982
|
+
* import { FaasReactClient } from '@faasjs/react'
|
|
983
|
+
*
|
|
969
984
|
* const client = FaasReactClient({
|
|
970
|
-
* baseUrl: 'localhost:8080/api/'
|
|
985
|
+
* baseUrl: 'http://localhost:8080/api/',
|
|
971
986
|
* })
|
|
972
987
|
* ```
|
|
973
988
|
*/
|
|
@@ -996,16 +1011,20 @@ function FaasReactClient({ baseUrl, options: clientOptions, onError } = { baseUr
|
|
|
996
1011
|
return reactClient;
|
|
997
1012
|
}
|
|
998
1013
|
/**
|
|
999
|
-
* Get FaasReactClient instance
|
|
1014
|
+
* Get a registered FaasReactClient instance.
|
|
1000
1015
|
*
|
|
1001
|
-
*
|
|
1002
|
-
*
|
|
1016
|
+
* When `host` is omitted, the first registered client is returned. If no client
|
|
1017
|
+
* has been created yet, a default client is initialized automatically.
|
|
1018
|
+
*
|
|
1019
|
+
* @param host - Registered base URL to look up. Omit it to use the default client.
|
|
1020
|
+
* @returns Registered or newly created FaasReactClient instance.
|
|
1003
1021
|
*
|
|
1004
1022
|
* @example
|
|
1005
1023
|
* ```ts
|
|
1024
|
+
* import { getClient } from '@faasjs/react'
|
|
1025
|
+
*
|
|
1006
1026
|
* getClient()
|
|
1007
|
-
*
|
|
1008
|
-
* getClient('another-host')
|
|
1027
|
+
* getClient('http://localhost:8080/api/')
|
|
1009
1028
|
* ```
|
|
1010
1029
|
*/
|
|
1011
1030
|
function getClient(host) {
|
|
@@ -1061,53 +1080,46 @@ var ErrorBoundary = class extends react.Component {
|
|
|
1061
1080
|
}
|
|
1062
1081
|
};
|
|
1063
1082
|
//#endregion
|
|
1064
|
-
//#region src/
|
|
1083
|
+
//#region src/OptionalWrapper.tsx
|
|
1065
1084
|
/**
|
|
1066
|
-
*
|
|
1067
|
-
*
|
|
1068
|
-
* @template T - The type of the value.
|
|
1069
|
-
* @param {T} initialValue - The initial value of the state.
|
|
1070
|
-
* @returns {[T, (value: T) => void, RefObject<T>]} - The stateful value, a function to set the value, and a ref to the value.
|
|
1085
|
+
* A wrapper component that conditionally wraps its children with a provided wrapper component.
|
|
1071
1086
|
*
|
|
1072
1087
|
* @example
|
|
1073
1088
|
* ```tsx
|
|
1074
|
-
* import {
|
|
1089
|
+
* import { OptionalWrapper } from '@faasjs/react'
|
|
1075
1090
|
*
|
|
1076
|
-
*
|
|
1077
|
-
*
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1082
|
-
* <
|
|
1083
|
-
*
|
|
1084
|
-
* </div>
|
|
1091
|
+
* const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
1092
|
+
* <div className='wrapper'>{children}</div>
|
|
1093
|
+
* )
|
|
1094
|
+
*
|
|
1095
|
+
* const App = () => (
|
|
1096
|
+
* <OptionalWrapper condition={true} Wrapper={Wrapper}>
|
|
1097
|
+
* <span>Test</span>
|
|
1098
|
+
* </OptionalWrapper>
|
|
1085
1099
|
* )
|
|
1100
|
+
* ```
|
|
1086
1101
|
*/
|
|
1087
|
-
function
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
return [
|
|
1094
|
-
state,
|
|
1095
|
-
setState,
|
|
1096
|
-
ref
|
|
1097
|
-
];
|
|
1102
|
+
function OptionalWrapper({ condition, Wrapper, wrapperProps, children }) {
|
|
1103
|
+
if (condition) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Wrapper, {
|
|
1104
|
+
...wrapperProps,
|
|
1105
|
+
children
|
|
1106
|
+
});
|
|
1107
|
+
return children;
|
|
1098
1108
|
}
|
|
1109
|
+
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1099
1110
|
//#endregion
|
|
1100
1111
|
//#region src/splittingState.tsx
|
|
1101
1112
|
/**
|
|
1102
|
-
*
|
|
1113
|
+
* Create local state entries and matching setters for each key in an object.
|
|
1103
1114
|
*
|
|
1104
1115
|
* @template T - A generic type that extends a record with string keys and any values.
|
|
1105
|
-
* @param
|
|
1116
|
+
* @param initialStates - Object whose keys become state values and `setXxx` setters.
|
|
1117
|
+
* @returns Object containing the original keys plus generated setter functions.
|
|
1106
1118
|
*
|
|
1107
1119
|
* @example
|
|
1108
1120
|
* ```tsx
|
|
1109
1121
|
* function Counter() {
|
|
1110
|
-
* const { count, setCount, name, setName } = useSplittingState({ count: 0, name: 'John' })
|
|
1122
|
+
* const { count, setCount, name, setName } = useSplittingState({ count: 0, name: 'John' })
|
|
1111
1123
|
*
|
|
1112
1124
|
* return <>{name}: {count}</>
|
|
1113
1125
|
* }
|
|
@@ -1207,291 +1219,23 @@ function createSplittingContext(defaultValue) {
|
|
|
1207
1219
|
};
|
|
1208
1220
|
}
|
|
1209
1221
|
//#endregion
|
|
1210
|
-
//#region src/
|
|
1211
|
-
const FormContext = createSplittingContext([
|
|
1212
|
-
"items",
|
|
1213
|
-
"onSubmit",
|
|
1214
|
-
"Elements",
|
|
1215
|
-
"lang",
|
|
1216
|
-
"rules",
|
|
1217
|
-
"submitting",
|
|
1218
|
-
"setSubmitting",
|
|
1219
|
-
"values",
|
|
1220
|
-
"setValues",
|
|
1221
|
-
"errors",
|
|
1222
|
-
"setErrors",
|
|
1223
|
-
"valuesRef"
|
|
1224
|
-
]);
|
|
1225
|
-
const FormContextProvider = FormContext.Provider;
|
|
1226
|
-
const useFormContext = FormContext.use;
|
|
1227
|
-
//#endregion
|
|
1228
|
-
//#region src/Form/Input.tsx
|
|
1229
|
-
function processValue(input, rules) {
|
|
1230
|
-
switch (rules?.type) {
|
|
1231
|
-
case "number": return Number(input);
|
|
1232
|
-
case "string": return String(input);
|
|
1233
|
-
default: return input;
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
function FormInput({ name, rules, ...rest }) {
|
|
1237
|
-
const { Elements, values, setValues } = useFormContext();
|
|
1238
|
-
const value = values?.[name];
|
|
1239
|
-
if (rest.Input) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(rest.Input, {
|
|
1240
|
-
name,
|
|
1241
|
-
value,
|
|
1242
|
-
onChange: (v) => setValues((prev) => ({
|
|
1243
|
-
...prev,
|
|
1244
|
-
[name]: processValue(v, rules)
|
|
1245
|
-
})),
|
|
1246
|
-
...rest.props
|
|
1247
|
-
});
|
|
1248
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Elements.Input, {
|
|
1249
|
-
name,
|
|
1250
|
-
value,
|
|
1251
|
-
onChange: (v) => setValues((prev) => ({
|
|
1252
|
-
...prev,
|
|
1253
|
-
[name]: processValue(v, rules)
|
|
1254
|
-
})),
|
|
1255
|
-
...rest.props
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
FormInput.displayName = "FormInput";
|
|
1259
|
-
//#endregion
|
|
1260
|
-
//#region src/Form/Item.tsx
|
|
1261
|
-
function FormItem(props) {
|
|
1262
|
-
const { Elements, errors } = useFormContext();
|
|
1263
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(props.label?.Label ?? Elements.Label, {
|
|
1264
|
-
name: props.name,
|
|
1265
|
-
...props.label,
|
|
1266
|
-
error: errors[props.name],
|
|
1267
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormInput, {
|
|
1268
|
-
name: props.name,
|
|
1269
|
-
...props.input,
|
|
1270
|
-
...props.rules ? { rules: props.rules } : {}
|
|
1271
|
-
})
|
|
1272
|
-
});
|
|
1273
|
-
}
|
|
1274
|
-
FormItem.displayName = "FormItem";
|
|
1275
|
-
//#endregion
|
|
1276
|
-
//#region src/Form/Body.tsx
|
|
1277
|
-
function FormBody() {
|
|
1278
|
-
const { items } = useFormContext();
|
|
1279
|
-
return items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormItem, { ...item }, item.name));
|
|
1280
|
-
}
|
|
1281
|
-
FormBody.displayName = "FormBody";
|
|
1282
|
-
//#endregion
|
|
1283
|
-
//#region src/Form/elements/Button.tsx
|
|
1284
|
-
const FormButtonElement = (0, react.forwardRef)(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1285
|
-
type: "button",
|
|
1286
|
-
disabled: submitting,
|
|
1287
|
-
onClick: submit,
|
|
1288
|
-
...props,
|
|
1289
|
-
ref,
|
|
1290
|
-
children
|
|
1291
|
-
}));
|
|
1292
|
-
FormButtonElement.displayName = "FormButtonElement";
|
|
1293
|
-
//#endregion
|
|
1294
|
-
//#region src/Form/elements/Input.tsx
|
|
1295
|
-
const FormInputElement = (0, react.forwardRef)(({ onChange, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1296
|
-
...props,
|
|
1297
|
-
onChange: (e) => onChange(e.target.value),
|
|
1298
|
-
ref
|
|
1299
|
-
}));
|
|
1300
|
-
FormInputElement.displayName = "FormInputElement";
|
|
1301
|
-
//#endregion
|
|
1302
|
-
//#region src/Form/elements/Label.tsx
|
|
1303
|
-
const FormLabelElement = ({ name, title, description, error, children }) => {
|
|
1304
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
|
|
1305
|
-
title ?? name,
|
|
1306
|
-
children,
|
|
1307
|
-
description,
|
|
1308
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1309
|
-
style: { color: "red" },
|
|
1310
|
-
children: error.message
|
|
1311
|
-
})
|
|
1312
|
-
] });
|
|
1313
|
-
};
|
|
1314
|
-
FormLabelElement.displayName = "FormLabelElement";
|
|
1315
|
-
//#endregion
|
|
1316
|
-
//#region src/Form/elements/index.ts
|
|
1317
|
-
const FormDefaultElements = {
|
|
1318
|
-
Label: FormLabelElement,
|
|
1319
|
-
Input: FormInputElement,
|
|
1320
|
-
Button: FormButtonElement
|
|
1321
|
-
};
|
|
1322
|
-
//#endregion
|
|
1323
|
-
//#region src/Form/rules.ts
|
|
1324
|
-
/**
|
|
1325
|
-
* Default validation rules for a form.
|
|
1326
|
-
*/
|
|
1327
|
-
const FormDefaultRules = {
|
|
1328
|
-
required: async (value, _, lang) => {
|
|
1329
|
-
if (value === null || value === void 0 || value === "" || Number.isNaN(value)) throw Error(lang?.required);
|
|
1330
|
-
},
|
|
1331
|
-
type: async (value, options, lang) => {
|
|
1332
|
-
switch (options) {
|
|
1333
|
-
case "string":
|
|
1334
|
-
if (typeof value !== "string") throw Error(lang?.string);
|
|
1335
|
-
break;
|
|
1336
|
-
case "number":
|
|
1337
|
-
if (Number.isNaN(Number(value))) throw Error(lang?.number);
|
|
1338
|
-
break;
|
|
1339
|
-
}
|
|
1340
|
-
},
|
|
1341
|
-
custom: async (value, options) => {
|
|
1342
|
-
return options(value);
|
|
1343
|
-
}
|
|
1344
|
-
};
|
|
1345
|
-
async function validValues(rules, items, values, lang) {
|
|
1346
|
-
const errors = {};
|
|
1347
|
-
for (const item of items) {
|
|
1348
|
-
const value = values[item.name];
|
|
1349
|
-
const rulesOptions = item.rules;
|
|
1350
|
-
if (rulesOptions) for (const [name, options] of Object.entries(rulesOptions)) try {
|
|
1351
|
-
await rules[name](value, options, lang);
|
|
1352
|
-
} catch (error) {
|
|
1353
|
-
errors[item.name] = error;
|
|
1354
|
-
break;
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
return errors;
|
|
1358
|
-
}
|
|
1359
|
-
//#endregion
|
|
1360
|
-
//#region src/Form/Footer.tsx
|
|
1361
|
-
function FormFooter() {
|
|
1362
|
-
const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
|
|
1363
|
-
const Button = Elements.Button;
|
|
1364
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
1365
|
-
submitting,
|
|
1366
|
-
submit: (0, react.useCallback)(async () => {
|
|
1367
|
-
setSubmitting(true);
|
|
1368
|
-
setErrors({});
|
|
1369
|
-
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1370
|
-
if (Object.keys(errors).length) {
|
|
1371
|
-
setErrors(errors);
|
|
1372
|
-
setSubmitting(false);
|
|
1373
|
-
return;
|
|
1374
|
-
}
|
|
1375
|
-
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1376
|
-
}, [
|
|
1377
|
-
setSubmitting,
|
|
1378
|
-
setErrors,
|
|
1379
|
-
rules,
|
|
1380
|
-
items,
|
|
1381
|
-
valuesRef,
|
|
1382
|
-
lang,
|
|
1383
|
-
onSubmit
|
|
1384
|
-
]),
|
|
1385
|
-
children: lang.submit
|
|
1386
|
-
});
|
|
1387
|
-
}
|
|
1388
|
-
FormFooter.displayName = "FormFooter";
|
|
1389
|
-
//#endregion
|
|
1390
|
-
//#region src/Form/lang.ts
|
|
1391
|
-
const FormDefaultLang = {
|
|
1392
|
-
submit: "Submit",
|
|
1393
|
-
required: "This field is required",
|
|
1394
|
-
string: "This field must be a string",
|
|
1395
|
-
number: "This field must be a number"
|
|
1396
|
-
};
|
|
1397
|
-
//#endregion
|
|
1398
|
-
//#region src/Form/Container.tsx
|
|
1399
|
-
function mergeValues(items, defaultValues = {}) {
|
|
1400
|
-
const values = {};
|
|
1401
|
-
for (const item of items) values[item.name] = defaultValues[item.name] ?? "";
|
|
1402
|
-
return values;
|
|
1403
|
-
}
|
|
1222
|
+
//#region src/useFaasStream.tsx
|
|
1404
1223
|
/**
|
|
1405
|
-
*
|
|
1406
|
-
* It initializes form states such as values, errors, submitting status, elements, language, and rules.
|
|
1407
|
-
*
|
|
1408
|
-
* @template Values - The type of form values, defaults to Record<string, any>.
|
|
1409
|
-
* @template FormElements - The type of form elements, defaults to FormElementTypes.
|
|
1410
|
-
* @template Rules - The type of form rules, defaults to FormDefaultRules.
|
|
1224
|
+
* Stream a FaasJS response into React state.
|
|
1411
1225
|
*
|
|
1412
|
-
*
|
|
1413
|
-
*
|
|
1414
|
-
* @param {FormElements} props.Elements - The form elements to be used in the form.
|
|
1415
|
-
* @param {Rules} props.rules - The validation rules for the form fields.
|
|
1416
|
-
* @param {FormLang} props.lang - The language settings for the form.
|
|
1417
|
-
* @param {Partial<FormContextProps>} props - Additional properties for the form context.
|
|
1226
|
+
* The hook sends a streaming request, appends decoded text chunks to `data`,
|
|
1227
|
+
* and exposes reload helpers for retrying the same action.
|
|
1418
1228
|
*
|
|
1419
|
-
* @
|
|
1229
|
+
* @param action - Action path to invoke.
|
|
1230
|
+
* @param defaultParams - Params used for the initial request and future reloads.
|
|
1231
|
+
* @param options - Optional hook configuration such as controlled data, debounce, and skip logic.
|
|
1232
|
+
* @returns Streaming request state and helper methods.
|
|
1420
1233
|
*
|
|
1421
1234
|
* @example
|
|
1422
1235
|
* ```tsx
|
|
1423
|
-
* import {
|
|
1424
|
-
*
|
|
1425
|
-
* function MyForm() {
|
|
1426
|
-
* return <Form
|
|
1427
|
-
* items={[
|
|
1428
|
-
* { name: 'name' },
|
|
1429
|
-
* ]}
|
|
1430
|
-
* />
|
|
1431
|
-
* }
|
|
1432
|
-
* ```
|
|
1433
|
-
*/
|
|
1434
|
-
function FormContainer({ defaultValues, Elements, rules, lang, items, ...props }) {
|
|
1435
|
-
const [values, setValues, valuesRef] = useStateRef(mergeValues(items, defaultValues));
|
|
1436
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(FormContextProvider, {
|
|
1437
|
-
initializeStates: {
|
|
1438
|
-
errors: {},
|
|
1439
|
-
submitting: false
|
|
1440
|
-
},
|
|
1441
|
-
value: {
|
|
1442
|
-
Elements: Object.assign(FormDefaultElements, Elements),
|
|
1443
|
-
lang: Object.assign(FormDefaultLang, lang),
|
|
1444
|
-
rules: Object.assign(FormDefaultRules, rules),
|
|
1445
|
-
items,
|
|
1446
|
-
values,
|
|
1447
|
-
setValues,
|
|
1448
|
-
valuesRef,
|
|
1449
|
-
...props
|
|
1450
|
-
},
|
|
1451
|
-
memo: true,
|
|
1452
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormBody, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormFooter, {})]
|
|
1453
|
-
});
|
|
1454
|
-
}
|
|
1455
|
-
FormContainer.displayName = "FormContainer";
|
|
1456
|
-
//#endregion
|
|
1457
|
-
//#region src/OptionalWrapper.tsx
|
|
1458
|
-
/**
|
|
1459
|
-
* A wrapper component that conditionally wraps its children with a provided wrapper component.
|
|
1460
|
-
*
|
|
1461
|
-
* @example
|
|
1462
|
-
* ```tsx
|
|
1463
|
-
* import { OptionalWrapper } from '@faasjs/react'
|
|
1464
|
-
*
|
|
1465
|
-
* const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
1466
|
-
* <div className='wrapper'>{children}</div>
|
|
1467
|
-
* )
|
|
1468
|
-
*
|
|
1469
|
-
* const App = () => (
|
|
1470
|
-
* <OptionalWrapper condition={true} Wrapper={Wrapper}>
|
|
1471
|
-
* <span>Test</span>
|
|
1472
|
-
* </OptionalWrapper>
|
|
1473
|
-
* )
|
|
1474
|
-
* ```
|
|
1475
|
-
*/
|
|
1476
|
-
function OptionalWrapper({ condition, Wrapper, wrapperProps, children }) {
|
|
1477
|
-
if (condition) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Wrapper, {
|
|
1478
|
-
...wrapperProps,
|
|
1479
|
-
children
|
|
1480
|
-
});
|
|
1481
|
-
return children;
|
|
1482
|
-
}
|
|
1483
|
-
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1484
|
-
//#endregion
|
|
1485
|
-
//#region src/useFaasStream.tsx
|
|
1486
|
-
/**
|
|
1487
|
-
* Stream faas server response with React hook
|
|
1236
|
+
* import { useState } from 'react'
|
|
1237
|
+
* import { useFaasStream } from '@faasjs/react'
|
|
1488
1238
|
*
|
|
1489
|
-
* @param action {string} action name
|
|
1490
|
-
* @param defaultParams {object} initial action params
|
|
1491
|
-
* @returns {UseFaasStreamResult}
|
|
1492
|
-
*
|
|
1493
|
-
* @example
|
|
1494
|
-
* ```tsx
|
|
1495
1239
|
* function Chat() {
|
|
1496
1240
|
* const [prompt, setPrompt] = useState('')
|
|
1497
1241
|
* const { data, loading, reload } = useFaasStream('chat', { prompt })
|
|
@@ -1632,8 +1376,8 @@ function useFaasStream(action, defaultParams, options = {}) {
|
|
|
1632
1376
|
* Hook to store the previous value of a state or prop.
|
|
1633
1377
|
*
|
|
1634
1378
|
* @template T - The type of the value.
|
|
1635
|
-
* @param
|
|
1636
|
-
* @returns
|
|
1379
|
+
* @param value - The current value to track.
|
|
1380
|
+
* @returns Previous value from the prior render, or `undefined` on the first render.
|
|
1637
1381
|
*/
|
|
1638
1382
|
function usePrevious(value) {
|
|
1639
1383
|
const ref = (0, react.useRef)(void 0);
|
|
@@ -1643,17 +1387,48 @@ function usePrevious(value) {
|
|
|
1643
1387
|
return ref.current;
|
|
1644
1388
|
}
|
|
1645
1389
|
//#endregion
|
|
1390
|
+
//#region src/useStateRef.ts
|
|
1391
|
+
/**
|
|
1392
|
+
* Custom hook that returns a stateful value and a ref to that value.
|
|
1393
|
+
*
|
|
1394
|
+
* @template T - The type of the value.
|
|
1395
|
+
* @param initialValue - Initial state value. When omitted, state starts as `null`.
|
|
1396
|
+
* @returns Tuple containing the current state, the state setter, and a ref that always points at the latest state.
|
|
1397
|
+
*
|
|
1398
|
+
* @example
|
|
1399
|
+
* ```tsx
|
|
1400
|
+
* import { useStateRef } from '@faasjs/react'
|
|
1401
|
+
*
|
|
1402
|
+
* function MyComponent() {
|
|
1403
|
+
* const [value, setValue, ref] = useStateRef(0)
|
|
1404
|
+
*
|
|
1405
|
+
* return (
|
|
1406
|
+
* <div>
|
|
1407
|
+
* <p>Value: {value}</p>
|
|
1408
|
+
* <button onClick={() => setValue(value + 1)}>Increment</button>
|
|
1409
|
+
* <button onClick={() => console.log(ref.current)}>Submit</button>
|
|
1410
|
+
* </div>
|
|
1411
|
+
* )
|
|
1412
|
+
* }
|
|
1413
|
+
* ```
|
|
1414
|
+
*/
|
|
1415
|
+
function useStateRef(initialValue) {
|
|
1416
|
+
const [state, setState] = (0, react.useState)(initialValue ?? null);
|
|
1417
|
+
const ref = (0, react.useRef)(state);
|
|
1418
|
+
(0, react.useEffect)(() => {
|
|
1419
|
+
ref.current = state;
|
|
1420
|
+
}, [state]);
|
|
1421
|
+
return [
|
|
1422
|
+
state,
|
|
1423
|
+
setState,
|
|
1424
|
+
ref
|
|
1425
|
+
];
|
|
1426
|
+
}
|
|
1427
|
+
//#endregion
|
|
1646
1428
|
exports.ErrorBoundary = ErrorBoundary;
|
|
1647
1429
|
exports.FaasBrowserClient = FaasBrowserClient;
|
|
1648
1430
|
exports.FaasDataWrapper = FaasDataWrapper;
|
|
1649
1431
|
exports.FaasReactClient = FaasReactClient;
|
|
1650
|
-
exports.Form = FormContainer;
|
|
1651
|
-
exports.FormContextProvider = FormContextProvider;
|
|
1652
|
-
exports.FormDefaultElements = FormDefaultElements;
|
|
1653
|
-
exports.FormDefaultLang = FormDefaultLang;
|
|
1654
|
-
exports.FormDefaultRules = FormDefaultRules;
|
|
1655
|
-
exports.FormInput = FormInput;
|
|
1656
|
-
exports.FormItem = FormItem;
|
|
1657
1432
|
exports.OptionalWrapper = OptionalWrapper;
|
|
1658
1433
|
exports.Response = Response;
|
|
1659
1434
|
exports.ResponseError = ResponseError;
|
|
@@ -1670,9 +1445,7 @@ exports.useEqualMemo = useEqualMemo;
|
|
|
1670
1445
|
exports.useEqualMemoize = useEqualMemoize;
|
|
1671
1446
|
exports.useFaas = useFaas;
|
|
1672
1447
|
exports.useFaasStream = useFaasStream;
|
|
1673
|
-
exports.useFormContext = useFormContext;
|
|
1674
1448
|
exports.usePrevious = usePrevious;
|
|
1675
1449
|
exports.useSplittingState = useSplittingState;
|
|
1676
1450
|
exports.useStateRef = useStateRef;
|
|
1677
|
-
exports.validValues = validValues;
|
|
1678
1451
|
exports.withFaasData = withFaasData;
|