@faasjs/react 8.0.0-beta.13 → 8.0.0-beta.15
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 -41
- package/dist/index.cjs +47 -68
- package/dist/index.d.ts +19 -19
- package/dist/index.mjs +47 -71
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -1,46 +1,5 @@
|
|
|
1
1
|
# @faasjs/react
|
|
2
2
|
|
|
3
|
-
React plugin for FaasJS.
|
|
4
|
-
|
|
5
|
-
[](https://github.com/faasjs/faasjs/blob/main/packages/react/LICENSE)
|
|
6
|
-
[](https://www.npmjs.com/package/@faasjs/react)
|
|
7
|
-
|
|
8
|
-
Includes browser client utilities (`FaasBrowserClient`, `ResponseError`, `setMock`) and React helpers.
|
|
9
|
-
|
|
10
|
-
## Features
|
|
11
|
-
|
|
12
|
-
- Support [FaasJS Request Specifications](https://faasjs.com/guide/request-spec.html).
|
|
13
|
-
- Support global and per-request configurations.
|
|
14
|
-
- Compatible with [why-did-you-render](https://github.com/welldone-software/why-did-you-render).
|
|
15
|
-
- Additional React functions:
|
|
16
|
-
- Utils:
|
|
17
|
-
- `equal`: Compare two values for deep equality.
|
|
18
|
-
- `createSplittingContext`: Create a context for code splitting.
|
|
19
|
-
- `useSplittingState`: Create splitting states.
|
|
20
|
-
- Hooks:
|
|
21
|
-
- `useEqualMemoize`: Memoize a value with deep equality.
|
|
22
|
-
- `useEqualEffect`: Run an effect with deep equality.
|
|
23
|
-
- `useEqualMemo`: Memoize a value with deep equality.
|
|
24
|
-
- `useEqualCallback`: Memoize a callback with deep equality.
|
|
25
|
-
- `useConstant`: Create a constant value with hooks.
|
|
26
|
-
- `usePrevious`: Get the previous value of a state.
|
|
27
|
-
- `useStateRef`: Create a state with a ref.
|
|
28
|
-
- Components:
|
|
29
|
-
- `OptionalWrapper`: Render a component optionally.
|
|
30
|
-
- `ErrorBoundary`: Catch errors in the component tree.
|
|
31
|
-
- Fetch Data:
|
|
32
|
-
- `faas`: Fetch data from FaasJS.
|
|
33
|
-
- `useFaas`: Fetch data from FaasJS with hooks.
|
|
34
|
-
- `useFaasStream`: Fetch streaming data from FaasJS with hooks.
|
|
35
|
-
- `FaasDataWrapper`: Fetch data from FaasJS with a wrapper component.
|
|
36
|
-
- `withFaasData`: Fetch data from FaasJS using a higher-order component (HOC).
|
|
37
|
-
|
|
38
|
-
## Install
|
|
39
|
-
|
|
40
|
-
```sh
|
|
41
|
-
npm install @faasjs/react react
|
|
42
|
-
```
|
|
43
|
-
|
|
44
3
|
## Functions
|
|
45
4
|
|
|
46
5
|
- [createSplittingContext](functions/createSplittingContext.md)
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value:
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let react = require("react");
|
|
3
3
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
4
|
-
|
|
5
4
|
//#region src/generateId.ts
|
|
6
5
|
/**
|
|
7
6
|
* Generate random id with prefix
|
|
@@ -18,7 +17,6 @@ function generateId(prefix = "", length = 18) {
|
|
|
18
17
|
if (length < 8 || length > 18) throw new Error("Length must be 8 ~ 18");
|
|
19
18
|
return `${prefix}${Date.now().toString(36).padStart(8, "0")}${Math.random().toString(36).substring(2, length - 6).padEnd(length - 8, "0")}`;
|
|
20
19
|
}
|
|
21
|
-
|
|
22
20
|
//#endregion
|
|
23
21
|
//#region src/browser.ts
|
|
24
22
|
/**
|
|
@@ -41,7 +39,7 @@ function generateId(prefix = "", length = 18) {
|
|
|
41
39
|
* @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
|
|
42
40
|
* All properties are optional with sensible defaults.
|
|
43
41
|
*
|
|
44
|
-
*
|
|
42
|
+
* Notes:
|
|
45
43
|
* - status defaults to 200 if data or body is present, 204 otherwise
|
|
46
44
|
* - body is automatically populated from data if not explicitly provided
|
|
47
45
|
* - headers defaults to an empty object if not provided
|
|
@@ -159,7 +157,7 @@ var Response = class {
|
|
|
159
157
|
* including HTTP status code, response headers, response body, and the original error.
|
|
160
158
|
*
|
|
161
159
|
* @class ResponseError
|
|
162
|
-
* @
|
|
160
|
+
* @augments Error
|
|
163
161
|
*
|
|
164
162
|
* @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
|
|
165
163
|
* @property {ResponseHeaders} headers - The response headers from the failed request.
|
|
@@ -240,7 +238,7 @@ var Response = class {
|
|
|
240
238
|
* })
|
|
241
239
|
* ```
|
|
242
240
|
*
|
|
243
|
-
*
|
|
241
|
+
* Notes:
|
|
244
242
|
* - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
|
|
245
243
|
* - The error message from server responses is extracted from body.error.message if available
|
|
246
244
|
* - When created from an Error object, the original error is preserved in the originalError property
|
|
@@ -263,7 +261,7 @@ var ResponseError = class extends Error {
|
|
|
263
261
|
message: data,
|
|
264
262
|
...options
|
|
265
263
|
};
|
|
266
|
-
else if (data instanceof Error || data
|
|
264
|
+
else if (data instanceof Error || typeof data === "object" && data !== null && typeof data.constructor?.name === "string" && data.constructor.name.includes("Error")) props = {
|
|
267
265
|
message: data.message,
|
|
268
266
|
originalError: data,
|
|
269
267
|
...options
|
|
@@ -346,7 +344,7 @@ function setMock(handler) {
|
|
|
346
344
|
* - Streaming support for large responses
|
|
347
345
|
* - Multiple instance support with unique IDs
|
|
348
346
|
*
|
|
349
|
-
*
|
|
347
|
+
* Notes:
|
|
350
348
|
* - All requests are POST requests by default
|
|
351
349
|
* - Automatically adds X-FaasJS-Request-Id header for request tracking
|
|
352
350
|
* - baseUrl must end with '/' (will throw Error if not)
|
|
@@ -490,7 +488,7 @@ var FaasBrowserClient = class {
|
|
|
490
488
|
* @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
|
|
491
489
|
* @throws {NetworkError} When network request fails
|
|
492
490
|
*
|
|
493
|
-
*
|
|
491
|
+
* Notes:
|
|
494
492
|
* - All requests are POST requests by default
|
|
495
493
|
* - Action path is automatically converted to lowercase
|
|
496
494
|
* - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
|
|
@@ -649,7 +647,7 @@ var FaasBrowserClient = class {
|
|
|
649
647
|
headers,
|
|
650
648
|
body
|
|
651
649
|
}));
|
|
652
|
-
} catch
|
|
650
|
+
} catch {
|
|
653
651
|
return Promise.reject(new ResponseError({
|
|
654
652
|
message: res,
|
|
655
653
|
status: response.status,
|
|
@@ -661,7 +659,6 @@ var FaasBrowserClient = class {
|
|
|
661
659
|
});
|
|
662
660
|
}
|
|
663
661
|
};
|
|
664
|
-
|
|
665
662
|
//#endregion
|
|
666
663
|
//#region src/faas.ts
|
|
667
664
|
/**
|
|
@@ -687,7 +684,6 @@ async function faas(action, params, options) {
|
|
|
687
684
|
});
|
|
688
685
|
return client.browserClient.action(action, params, options);
|
|
689
686
|
}
|
|
690
|
-
|
|
691
687
|
//#endregion
|
|
692
688
|
//#region src/equal.ts
|
|
693
689
|
const AsyncFunction = (async () => {}).constructor;
|
|
@@ -737,13 +733,18 @@ function equal(a, b) {
|
|
|
737
733
|
* @returns The memoized value.
|
|
738
734
|
*/
|
|
739
735
|
function useEqualMemoize(value) {
|
|
736
|
+
const ref = (0, react.useRef)(value);
|
|
737
|
+
if (!equal(value, ref.current)) ref.current = value;
|
|
738
|
+
return ref.current;
|
|
739
|
+
}
|
|
740
|
+
function useEqualSignal(value) {
|
|
740
741
|
const ref = (0, react.useRef)(value);
|
|
741
742
|
const signalRef = (0, react.useRef)(0);
|
|
742
743
|
if (!equal(value, ref.current)) {
|
|
743
744
|
ref.current = value;
|
|
744
745
|
signalRef.current += 1;
|
|
745
746
|
}
|
|
746
|
-
return
|
|
747
|
+
return signalRef.current;
|
|
747
748
|
}
|
|
748
749
|
/**
|
|
749
750
|
* Custom hook that works like `useEffect` but uses deep comparison on dependencies.
|
|
@@ -753,7 +754,7 @@ function useEqualMemoize(value) {
|
|
|
753
754
|
* @returns The result of the `useEffect` hook with memoized dependencies.
|
|
754
755
|
*/
|
|
755
756
|
function useEqualEffect(callback, dependencies) {
|
|
756
|
-
return (0, react.useEffect)(callback,
|
|
757
|
+
return (0, react.useEffect)(callback, [useEqualSignal(dependencies)]);
|
|
757
758
|
}
|
|
758
759
|
/**
|
|
759
760
|
* Custom hook that works like `useMemo` but uses deep comparison on dependencies.
|
|
@@ -763,7 +764,12 @@ function useEqualEffect(callback, dependencies) {
|
|
|
763
764
|
* @returns The result of the `useMemo` hook with memoized dependencies.
|
|
764
765
|
*/
|
|
765
766
|
function useEqualMemo(callback, dependencies) {
|
|
766
|
-
|
|
767
|
+
const signal = useEqualSignal(dependencies);
|
|
768
|
+
const callbackRef = (0, react.useRef)(callback);
|
|
769
|
+
callbackRef.current = callback;
|
|
770
|
+
return (0, react.useMemo)(() => {
|
|
771
|
+
return callbackRef.current();
|
|
772
|
+
}, [signal]);
|
|
767
773
|
}
|
|
768
774
|
/**
|
|
769
775
|
* Custom hook that works like `useCallback` but uses deep comparison on dependencies.
|
|
@@ -773,9 +779,8 @@ function useEqualMemo(callback, dependencies) {
|
|
|
773
779
|
* @returns The result of the `useCallback` hook with memoized dependencies.
|
|
774
780
|
*/
|
|
775
781
|
function useEqualCallback(callback, dependencies) {
|
|
776
|
-
return (0, react.useCallback)((...args) => callback(...args),
|
|
782
|
+
return (0, react.useCallback)((...args) => callback(...args), [useEqualSignal(dependencies)]);
|
|
777
783
|
}
|
|
778
|
-
|
|
779
784
|
//#endregion
|
|
780
785
|
//#region src/FaasDataWrapper.tsx
|
|
781
786
|
const fixedForwardRef = react.forwardRef;
|
|
@@ -823,7 +828,6 @@ function withFaasData(Component, faasProps) {
|
|
|
823
828
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, { ...props })
|
|
824
829
|
});
|
|
825
830
|
}
|
|
826
|
-
|
|
827
831
|
//#endregion
|
|
828
832
|
//#region src/useFaas.tsx
|
|
829
833
|
/**
|
|
@@ -877,7 +881,8 @@ function useFaas(action, defaultParams, options = {}) {
|
|
|
877
881
|
const nextData = r.data;
|
|
878
882
|
setFails(0);
|
|
879
883
|
setError(null);
|
|
880
|
-
options.setData
|
|
884
|
+
if (options.setData) options.setData(nextData);
|
|
885
|
+
else localSetData(nextData);
|
|
881
886
|
setLoading(false);
|
|
882
887
|
for (const { resolve } of pendingReloadsRef.current.values()) resolve(nextData);
|
|
883
888
|
pendingReloadsRef.current.clear();
|
|
@@ -951,7 +956,6 @@ function useFaas(action, defaultParams, options = {}) {
|
|
|
951
956
|
setError
|
|
952
957
|
};
|
|
953
958
|
}
|
|
954
|
-
|
|
955
959
|
//#endregion
|
|
956
960
|
//#region src/client.tsx
|
|
957
961
|
const clients = {};
|
|
@@ -1012,7 +1016,6 @@ function getClient(host) {
|
|
|
1012
1016
|
}
|
|
1013
1017
|
return client;
|
|
1014
1018
|
}
|
|
1015
|
-
|
|
1016
1019
|
//#endregion
|
|
1017
1020
|
//#region src/constant.ts
|
|
1018
1021
|
/**
|
|
@@ -1023,7 +1026,6 @@ function useConstant(fn) {
|
|
|
1023
1026
|
if (!ref.current) ref.current = { v: fn() };
|
|
1024
1027
|
return ref.current.v;
|
|
1025
1028
|
}
|
|
1026
|
-
|
|
1027
1029
|
//#endregion
|
|
1028
1030
|
//#region src/ErrorBoundary.tsx
|
|
1029
1031
|
var ErrorBoundary = class extends react.Component {
|
|
@@ -1058,7 +1060,6 @@ var ErrorBoundary = class extends react.Component {
|
|
|
1058
1060
|
return this.props.children ?? null;
|
|
1059
1061
|
}
|
|
1060
1062
|
};
|
|
1061
|
-
|
|
1062
1063
|
//#endregion
|
|
1063
1064
|
//#region src/useStateRef.ts
|
|
1064
1065
|
/**
|
|
@@ -1095,7 +1096,6 @@ function useStateRef(initialValue) {
|
|
|
1095
1096
|
ref
|
|
1096
1097
|
];
|
|
1097
1098
|
}
|
|
1098
|
-
|
|
1099
1099
|
//#endregion
|
|
1100
1100
|
//#region src/splittingState.tsx
|
|
1101
1101
|
/**
|
|
@@ -1124,7 +1124,6 @@ function useSplittingState(initialStates) {
|
|
|
1124
1124
|
}
|
|
1125
1125
|
return states;
|
|
1126
1126
|
}
|
|
1127
|
-
|
|
1128
1127
|
//#endregion
|
|
1129
1128
|
//#region src/splittingContext.tsx
|
|
1130
1129
|
/**
|
|
@@ -1207,7 +1206,6 @@ function createSplittingContext(defaultValue) {
|
|
|
1207
1206
|
use
|
|
1208
1207
|
};
|
|
1209
1208
|
}
|
|
1210
|
-
|
|
1211
1209
|
//#endregion
|
|
1212
1210
|
//#region src/Form/context.tsx
|
|
1213
1211
|
const FormContext = createSplittingContext([
|
|
@@ -1226,7 +1224,6 @@ const FormContext = createSplittingContext([
|
|
|
1226
1224
|
]);
|
|
1227
1225
|
const FormContextProvider = FormContext.Provider;
|
|
1228
1226
|
const useFormContext = FormContext.use;
|
|
1229
|
-
|
|
1230
1227
|
//#endregion
|
|
1231
1228
|
//#region src/Form/Input.tsx
|
|
1232
1229
|
function processValue(input, rules) {
|
|
@@ -1259,7 +1256,6 @@ function FormInput({ name, rules, ...rest }) {
|
|
|
1259
1256
|
});
|
|
1260
1257
|
}
|
|
1261
1258
|
FormInput.displayName = "FormInput";
|
|
1262
|
-
|
|
1263
1259
|
//#endregion
|
|
1264
1260
|
//#region src/Form/Item.tsx
|
|
1265
1261
|
function FormItem(props) {
|
|
@@ -1276,7 +1272,6 @@ function FormItem(props) {
|
|
|
1276
1272
|
});
|
|
1277
1273
|
}
|
|
1278
1274
|
FormItem.displayName = "FormItem";
|
|
1279
|
-
|
|
1280
1275
|
//#endregion
|
|
1281
1276
|
//#region src/Form/Body.tsx
|
|
1282
1277
|
function FormBody() {
|
|
@@ -1284,7 +1279,6 @@ function FormBody() {
|
|
|
1284
1279
|
return items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormItem, { ...item }, item.name));
|
|
1285
1280
|
}
|
|
1286
1281
|
FormBody.displayName = "FormBody";
|
|
1287
|
-
|
|
1288
1282
|
//#endregion
|
|
1289
1283
|
//#region src/Form/elements/Button.tsx
|
|
1290
1284
|
const FormButtonElement = (0, react.forwardRef)(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -1296,7 +1290,6 @@ const FormButtonElement = (0, react.forwardRef)(({ children, submit, submitting,
|
|
|
1296
1290
|
children
|
|
1297
1291
|
}));
|
|
1298
1292
|
FormButtonElement.displayName = "FormButtonElement";
|
|
1299
|
-
|
|
1300
1293
|
//#endregion
|
|
1301
1294
|
//#region src/Form/elements/Input.tsx
|
|
1302
1295
|
const FormInputElement = (0, react.forwardRef)(({ onChange, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
@@ -1305,7 +1298,6 @@ const FormInputElement = (0, react.forwardRef)(({ onChange, ...props }, ref) =>
|
|
|
1305
1298
|
ref
|
|
1306
1299
|
}));
|
|
1307
1300
|
FormInputElement.displayName = "FormInputElement";
|
|
1308
|
-
|
|
1309
1301
|
//#endregion
|
|
1310
1302
|
//#region src/Form/elements/Label.tsx
|
|
1311
1303
|
const FormLabelElement = ({ name, title, description, error, children }) => {
|
|
@@ -1320,7 +1312,6 @@ const FormLabelElement = ({ name, title, description, error, children }) => {
|
|
|
1320
1312
|
] });
|
|
1321
1313
|
};
|
|
1322
1314
|
FormLabelElement.displayName = "FormLabelElement";
|
|
1323
|
-
|
|
1324
1315
|
//#endregion
|
|
1325
1316
|
//#region src/Form/elements/index.ts
|
|
1326
1317
|
const FormDefaultElements = {
|
|
@@ -1328,7 +1319,6 @@ const FormDefaultElements = {
|
|
|
1328
1319
|
Input: FormInputElement,
|
|
1329
1320
|
Button: FormButtonElement
|
|
1330
1321
|
};
|
|
1331
|
-
|
|
1332
1322
|
//#endregion
|
|
1333
1323
|
//#region src/Form/rules.ts
|
|
1334
1324
|
/**
|
|
@@ -1366,42 +1356,36 @@ async function validValues(rules, items, values, lang) {
|
|
|
1366
1356
|
}
|
|
1367
1357
|
return errors;
|
|
1368
1358
|
}
|
|
1369
|
-
|
|
1370
1359
|
//#endregion
|
|
1371
1360
|
//#region src/Form/Footer.tsx
|
|
1372
1361
|
function FormFooter() {
|
|
1373
1362
|
const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
|
|
1374
|
-
const
|
|
1375
|
-
|
|
1376
|
-
setErrors({});
|
|
1377
|
-
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1378
|
-
if (Object.keys(errors).length) {
|
|
1379
|
-
setErrors(errors);
|
|
1380
|
-
setSubmitting(false);
|
|
1381
|
-
return;
|
|
1382
|
-
}
|
|
1383
|
-
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1384
|
-
}, [
|
|
1385
|
-
setSubmitting,
|
|
1386
|
-
setErrors,
|
|
1387
|
-
rules,
|
|
1388
|
-
items,
|
|
1389
|
-
lang,
|
|
1390
|
-
onSubmit
|
|
1391
|
-
]);
|
|
1392
|
-
return (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Elements.Button, {
|
|
1363
|
+
const Button = Elements.Button;
|
|
1364
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
1393
1365
|
submitting,
|
|
1394
|
-
submit:
|
|
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
|
+
]),
|
|
1395
1385
|
children: lang.submit
|
|
1396
|
-
})
|
|
1397
|
-
submitting,
|
|
1398
|
-
handleSubmit,
|
|
1399
|
-
lang.submit,
|
|
1400
|
-
Elements.Button
|
|
1401
|
-
]);
|
|
1386
|
+
});
|
|
1402
1387
|
}
|
|
1403
1388
|
FormFooter.displayName = "FormFooter";
|
|
1404
|
-
|
|
1405
1389
|
//#endregion
|
|
1406
1390
|
//#region src/Form/lang.ts
|
|
1407
1391
|
const FormDefaultLang = {
|
|
@@ -1410,7 +1394,6 @@ const FormDefaultLang = {
|
|
|
1410
1394
|
string: "This field must be a string",
|
|
1411
1395
|
number: "This field must be a number"
|
|
1412
1396
|
};
|
|
1413
|
-
|
|
1414
1397
|
//#endregion
|
|
1415
1398
|
//#region src/Form/Container.tsx
|
|
1416
1399
|
function mergeValues(items, defaultValues = {}) {
|
|
@@ -1470,7 +1453,6 @@ function FormContainer({ defaultValues, Elements, rules, lang, items, ...props }
|
|
|
1470
1453
|
});
|
|
1471
1454
|
}
|
|
1472
1455
|
FormContainer.displayName = "FormContainer";
|
|
1473
|
-
|
|
1474
1456
|
//#endregion
|
|
1475
1457
|
//#region src/OptionalWrapper.tsx
|
|
1476
1458
|
/**
|
|
@@ -1499,7 +1481,6 @@ function OptionalWrapper({ condition, Wrapper, wrapperProps, children }) {
|
|
|
1499
1481
|
return children;
|
|
1500
1482
|
}
|
|
1501
1483
|
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1502
|
-
|
|
1503
1484
|
//#endregion
|
|
1504
1485
|
//#region src/useFaasStream.tsx
|
|
1505
1486
|
/**
|
|
@@ -1645,7 +1626,6 @@ function useFaasStream(action, defaultParams, options = {}) {
|
|
|
1645
1626
|
setError
|
|
1646
1627
|
};
|
|
1647
1628
|
}
|
|
1648
|
-
|
|
1649
1629
|
//#endregion
|
|
1650
1630
|
//#region src/usePrevious.ts
|
|
1651
1631
|
/**
|
|
@@ -1662,7 +1642,6 @@ function usePrevious(value) {
|
|
|
1662
1642
|
});
|
|
1663
1643
|
return ref.current;
|
|
1664
1644
|
}
|
|
1665
|
-
|
|
1666
1645
|
//#endregion
|
|
1667
1646
|
exports.ErrorBoundary = ErrorBoundary;
|
|
1668
1647
|
exports.FaasBrowserClient = FaasBrowserClient;
|
|
@@ -1696,4 +1675,4 @@ exports.usePrevious = usePrevious;
|
|
|
1696
1675
|
exports.useSplittingState = useSplittingState;
|
|
1697
1676
|
exports.useStateRef = useStateRef;
|
|
1698
1677
|
exports.validValues = validValues;
|
|
1699
|
-
exports.withFaasData = withFaasData;
|
|
1678
|
+
exports.withFaasData = withFaasData;
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ declare function generateId(prefix?: string, length?: number): string;
|
|
|
24
24
|
* Ensures that base URLs used in FaasJS requests always have a trailing '/' character,
|
|
25
25
|
* which is required for proper URL construction when appending action paths.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
27
|
+
* Notes:
|
|
28
28
|
* - Type only accepts strings ending with '/' (e.g., 'https://api.example.com/', '/')
|
|
29
29
|
* - Strings without trailing '/' will fail TypeScript type checking
|
|
30
30
|
* - Used by FaasBrowserClient constructor and Options type
|
|
@@ -41,7 +41,7 @@ type BaseUrl = `${string}/`;
|
|
|
41
41
|
* Extends the standard RequestInit interface with FaasJS-specific options for
|
|
42
42
|
* customizing request behavior, adding request hooks, and overriding defaults.
|
|
43
43
|
*
|
|
44
|
-
*
|
|
44
|
+
* Notes:
|
|
45
45
|
* - Options can be provided at client creation (defaultOptions) or per-request
|
|
46
46
|
* - Per-request options override client default options
|
|
47
47
|
* - headers are merged: per-request headers override default headers
|
|
@@ -73,7 +73,7 @@ type BaseUrl = `${string}/`;
|
|
|
73
73
|
* Useful for processing large data incrementally or working with binary data streams.
|
|
74
74
|
* When false or undefined, returns a wrapped Response with automatic JSON parsing.
|
|
75
75
|
*
|
|
76
|
-
* @
|
|
76
|
+
* @augments RequestInit
|
|
77
77
|
* @see FaasBrowserClient for client creation
|
|
78
78
|
* @see Response for response object structure
|
|
79
79
|
*/
|
|
@@ -103,7 +103,7 @@ type Options = RequestInit & {
|
|
|
103
103
|
* @property {string} [key] - Dynamic string keys for header names (e.g., 'Content-Type', 'Authorization').
|
|
104
104
|
* Values must be strings. Multiple values for the same key are not supported.
|
|
105
105
|
*
|
|
106
|
-
*
|
|
106
|
+
* Notes:
|
|
107
107
|
* - Headers are case-insensitive in HTTP but stored with exact casing in this object
|
|
108
108
|
* - Common headers include: Content-Type, Authorization, X-Request-Id, X-Custom-Header
|
|
109
109
|
* - No support for multi-value headers (use comma-separated values instead)
|
|
@@ -131,7 +131,7 @@ type ResponseHeaders = {
|
|
|
131
131
|
*
|
|
132
132
|
* @returns {Promise<Response<FaasData<PathOrData>> | Response>} - A Promise resolving to a Response object
|
|
133
133
|
*
|
|
134
|
-
*
|
|
134
|
+
* Notes:
|
|
135
135
|
* - Used internally by FaasBrowserClient.action method
|
|
136
136
|
* - Provides type-safe action method signature
|
|
137
137
|
* - Return type includes both typed and untyped Response variants
|
|
@@ -163,7 +163,7 @@ type FaasBrowserClientAction = <PathOrData extends FaasActionUnionType$1>(action
|
|
|
163
163
|
* @property {T} [data] - The parsed JSON data to include in the response.
|
|
164
164
|
* Optional: contains the response payload when JSON data is provided.
|
|
165
165
|
*
|
|
166
|
-
*
|
|
166
|
+
* Notes:
|
|
167
167
|
* - All properties are optional
|
|
168
168
|
* - At least one of data or body should be provided for meaningful responses
|
|
169
169
|
* - The Response class automatically defaults status to 200 or 204 based on content
|
|
@@ -199,7 +199,7 @@ type ResponseProps<T = any> = {
|
|
|
199
199
|
* @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
|
|
200
200
|
* All properties are optional with sensible defaults.
|
|
201
201
|
*
|
|
202
|
-
*
|
|
202
|
+
* Notes:
|
|
203
203
|
* - status defaults to 200 if data or body is present, 204 otherwise
|
|
204
204
|
* - body is automatically populated from data if not explicitly provided
|
|
205
205
|
* - headers defaults to an empty object if not provided
|
|
@@ -318,7 +318,7 @@ type ResponseErrorProps = {
|
|
|
318
318
|
* including HTTP status code, response headers, response body, and the original error.
|
|
319
319
|
*
|
|
320
320
|
* @class ResponseError
|
|
321
|
-
* @
|
|
321
|
+
* @augments Error
|
|
322
322
|
*
|
|
323
323
|
* @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
|
|
324
324
|
* @property {ResponseHeaders} headers - The response headers from the failed request.
|
|
@@ -399,7 +399,7 @@ type ResponseErrorProps = {
|
|
|
399
399
|
* })
|
|
400
400
|
* ```
|
|
401
401
|
*
|
|
402
|
-
*
|
|
402
|
+
* Notes:
|
|
403
403
|
* - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
|
|
404
404
|
* - The error message from server responses is extracted from body.error.message if available
|
|
405
405
|
* - When created from an Error object, the original error is preserved in the originalError property
|
|
@@ -441,7 +441,7 @@ declare class ResponseError extends Error {
|
|
|
441
441
|
* - void: Returns an empty response (204 No Content)
|
|
442
442
|
* - Error: Throws ResponseError when returning an Error object
|
|
443
443
|
*
|
|
444
|
-
*
|
|
444
|
+
* Notes:
|
|
445
445
|
* - Used by setMock() function to mock API calls during tests
|
|
446
446
|
* - Affects all FaasBrowserClient instances when set globally
|
|
447
447
|
* - Can return different responses based on action or params
|
|
@@ -568,7 +568,7 @@ declare function setMock(handler: MockHandler | ResponseProps | Response | null)
|
|
|
568
568
|
* - Streaming support for large responses
|
|
569
569
|
* - Multiple instance support with unique IDs
|
|
570
570
|
*
|
|
571
|
-
*
|
|
571
|
+
* Notes:
|
|
572
572
|
* - All requests are POST requests by default
|
|
573
573
|
* - Automatically adds X-FaasJS-Request-Id header for request tracking
|
|
574
574
|
* - baseUrl must end with '/' (will throw Error if not)
|
|
@@ -706,7 +706,7 @@ declare class FaasBrowserClient {
|
|
|
706
706
|
* @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
|
|
707
707
|
* @throws {NetworkError} When network request fails
|
|
708
708
|
*
|
|
709
|
-
*
|
|
709
|
+
* Notes:
|
|
710
710
|
* - All requests are POST requests by default
|
|
711
711
|
* - Action path is automatically converted to lowercase
|
|
712
712
|
* - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
|
|
@@ -971,7 +971,7 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, {
|
|
|
971
971
|
static displayName: string;
|
|
972
972
|
constructor(props: ErrorBoundaryProps);
|
|
973
973
|
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
974
|
-
render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> |
|
|
974
|
+
render(): string | number | bigint | boolean | react_jsx_runtime0.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null;
|
|
975
975
|
}
|
|
976
976
|
//#endregion
|
|
977
977
|
//#region src/equal.d.ts
|
|
@@ -1228,13 +1228,13 @@ type FormContextProps<Values extends Record<string, any> = Record<string, any>,
|
|
|
1228
1228
|
setErrors: Dispatch<SetStateAction<Record<string, Error>>>;
|
|
1229
1229
|
valuesRef: RefObject<Values>;
|
|
1230
1230
|
};
|
|
1231
|
-
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(props: {
|
|
1231
|
+
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(this: void, props: {
|
|
1232
1232
|
value?: Partial<NewT>;
|
|
1233
1233
|
children: react.ReactNode;
|
|
1234
1234
|
memo?: true | any[];
|
|
1235
1235
|
initializeStates?: Partial<NewT>;
|
|
1236
1236
|
}) => react.ReactNode;
|
|
1237
|
-
declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>() => Readonly<NewT>;
|
|
1237
|
+
declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(this: void) => Readonly<NewT>;
|
|
1238
1238
|
//#endregion
|
|
1239
1239
|
//#region src/OptionalWrapper.d.ts
|
|
1240
1240
|
type OptionalWrapperProps<TWrapper extends ComponentType<{
|
|
@@ -1268,7 +1268,7 @@ declare function OptionalWrapper({
|
|
|
1268
1268
|
Wrapper,
|
|
1269
1269
|
wrapperProps,
|
|
1270
1270
|
children
|
|
1271
|
-
}: OptionalWrapperProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> |
|
|
1271
|
+
}: OptionalWrapperProps): string | number | bigint | boolean | react_jsx_runtime0.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
|
|
1272
1272
|
declare namespace OptionalWrapper {
|
|
1273
1273
|
var displayName: string;
|
|
1274
1274
|
}
|
|
@@ -1337,7 +1337,7 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
1337
1337
|
* }
|
|
1338
1338
|
* ```
|
|
1339
1339
|
*/
|
|
1340
|
-
Provider<NewT extends T = T>(props: {
|
|
1340
|
+
Provider<NewT extends T = T>(this: void, props: {
|
|
1341
1341
|
value?: Partial<NewT>;
|
|
1342
1342
|
children: ReactNode;
|
|
1343
1343
|
/**
|
|
@@ -1378,7 +1378,7 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
1378
1378
|
* }
|
|
1379
1379
|
* ```
|
|
1380
1380
|
*/
|
|
1381
|
-
use: <NewT extends T = T>() => Readonly<NewT>;
|
|
1381
|
+
use: <NewT extends T = T>(this: void) => Readonly<NewT>;
|
|
1382
1382
|
};
|
|
1383
1383
|
//#endregion
|
|
1384
1384
|
//#region src/splittingState.d.ts
|
|
@@ -1487,4 +1487,4 @@ declare function usePrevious<T = any>(value: T): T | undefined;
|
|
|
1487
1487
|
*/
|
|
1488
1488
|
declare function useStateRef<T = any>(initialValue?: T): [T | null, Dispatch<SetStateAction<T | null>>, RefObject<T | null>];
|
|
1489
1489
|
//#endregion
|
|
1490
|
-
export { BaseUrl, ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, FaasBrowserClient, FaasBrowserClientAction, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormDefaultRulesOptions, FormElementTypes, FormInput, type FormInputElementProps, FormInputProps, FormItem, FormItemName, FormItemProps, type FormLabelElementProps, FormLang,
|
|
1490
|
+
export { BaseUrl, ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, FaasBrowserClient, FaasBrowserClientAction, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormDefaultRulesOptions, FormElementTypes, FormInput, type FormInputElementProps, FormInputProps, FormItem, FormItemName, FormItemProps, type FormLabelElementProps, FormLang, FormProps, FormRule, FormRules, InferFormInputProps, InferFormRulesOptions, InferRuleOption, MockHandler, OnError, OptionalWrapper, OptionalWrapperProps, Options, Response, ResponseError, ResponseErrorProps, ResponseHeaders, ResponseProps, StateSetters, StatesWithSetters, UseFaasStreamOptions, UseFaasStreamResult, createSplittingContext, equal, faas, generateId, getClient, setMock, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasOptions, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Component, cloneElement, createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
|
|
4
3
|
//#region src/generateId.ts
|
|
5
4
|
/**
|
|
6
5
|
* Generate random id with prefix
|
|
@@ -17,7 +16,6 @@ function generateId(prefix = "", length = 18) {
|
|
|
17
16
|
if (length < 8 || length > 18) throw new Error("Length must be 8 ~ 18");
|
|
18
17
|
return `${prefix}${Date.now().toString(36).padStart(8, "0")}${Math.random().toString(36).substring(2, length - 6).padEnd(length - 8, "0")}`;
|
|
19
18
|
}
|
|
20
|
-
|
|
21
19
|
//#endregion
|
|
22
20
|
//#region src/browser.ts
|
|
23
21
|
/**
|
|
@@ -40,7 +38,7 @@ function generateId(prefix = "", length = 18) {
|
|
|
40
38
|
* @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
|
|
41
39
|
* All properties are optional with sensible defaults.
|
|
42
40
|
*
|
|
43
|
-
*
|
|
41
|
+
* Notes:
|
|
44
42
|
* - status defaults to 200 if data or body is present, 204 otherwise
|
|
45
43
|
* - body is automatically populated from data if not explicitly provided
|
|
46
44
|
* - headers defaults to an empty object if not provided
|
|
@@ -158,7 +156,7 @@ var Response = class {
|
|
|
158
156
|
* including HTTP status code, response headers, response body, and the original error.
|
|
159
157
|
*
|
|
160
158
|
* @class ResponseError
|
|
161
|
-
* @
|
|
159
|
+
* @augments Error
|
|
162
160
|
*
|
|
163
161
|
* @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
|
|
164
162
|
* @property {ResponseHeaders} headers - The response headers from the failed request.
|
|
@@ -239,7 +237,7 @@ var Response = class {
|
|
|
239
237
|
* })
|
|
240
238
|
* ```
|
|
241
239
|
*
|
|
242
|
-
*
|
|
240
|
+
* Notes:
|
|
243
241
|
* - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
|
|
244
242
|
* - The error message from server responses is extracted from body.error.message if available
|
|
245
243
|
* - When created from an Error object, the original error is preserved in the originalError property
|
|
@@ -262,7 +260,7 @@ var ResponseError = class extends Error {
|
|
|
262
260
|
message: data,
|
|
263
261
|
...options
|
|
264
262
|
};
|
|
265
|
-
else if (data instanceof Error || data
|
|
263
|
+
else if (data instanceof Error || typeof data === "object" && data !== null && typeof data.constructor?.name === "string" && data.constructor.name.includes("Error")) props = {
|
|
266
264
|
message: data.message,
|
|
267
265
|
originalError: data,
|
|
268
266
|
...options
|
|
@@ -345,7 +343,7 @@ function setMock(handler) {
|
|
|
345
343
|
* - Streaming support for large responses
|
|
346
344
|
* - Multiple instance support with unique IDs
|
|
347
345
|
*
|
|
348
|
-
*
|
|
346
|
+
* Notes:
|
|
349
347
|
* - All requests are POST requests by default
|
|
350
348
|
* - Automatically adds X-FaasJS-Request-Id header for request tracking
|
|
351
349
|
* - baseUrl must end with '/' (will throw Error if not)
|
|
@@ -489,7 +487,7 @@ var FaasBrowserClient = class {
|
|
|
489
487
|
* @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
|
|
490
488
|
* @throws {NetworkError} When network request fails
|
|
491
489
|
*
|
|
492
|
-
*
|
|
490
|
+
* Notes:
|
|
493
491
|
* - All requests are POST requests by default
|
|
494
492
|
* - Action path is automatically converted to lowercase
|
|
495
493
|
* - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
|
|
@@ -648,7 +646,7 @@ var FaasBrowserClient = class {
|
|
|
648
646
|
headers,
|
|
649
647
|
body
|
|
650
648
|
}));
|
|
651
|
-
} catch
|
|
649
|
+
} catch {
|
|
652
650
|
return Promise.reject(new ResponseError({
|
|
653
651
|
message: res,
|
|
654
652
|
status: response.status,
|
|
@@ -660,7 +658,6 @@ var FaasBrowserClient = class {
|
|
|
660
658
|
});
|
|
661
659
|
}
|
|
662
660
|
};
|
|
663
|
-
|
|
664
661
|
//#endregion
|
|
665
662
|
//#region src/faas.ts
|
|
666
663
|
/**
|
|
@@ -686,7 +683,6 @@ async function faas(action, params, options) {
|
|
|
686
683
|
});
|
|
687
684
|
return client.browserClient.action(action, params, options);
|
|
688
685
|
}
|
|
689
|
-
|
|
690
686
|
//#endregion
|
|
691
687
|
//#region src/equal.ts
|
|
692
688
|
const AsyncFunction = (async () => {}).constructor;
|
|
@@ -736,13 +732,18 @@ function equal(a, b) {
|
|
|
736
732
|
* @returns The memoized value.
|
|
737
733
|
*/
|
|
738
734
|
function useEqualMemoize(value) {
|
|
735
|
+
const ref = useRef(value);
|
|
736
|
+
if (!equal(value, ref.current)) ref.current = value;
|
|
737
|
+
return ref.current;
|
|
738
|
+
}
|
|
739
|
+
function useEqualSignal(value) {
|
|
739
740
|
const ref = useRef(value);
|
|
740
741
|
const signalRef = useRef(0);
|
|
741
742
|
if (!equal(value, ref.current)) {
|
|
742
743
|
ref.current = value;
|
|
743
744
|
signalRef.current += 1;
|
|
744
745
|
}
|
|
745
|
-
return
|
|
746
|
+
return signalRef.current;
|
|
746
747
|
}
|
|
747
748
|
/**
|
|
748
749
|
* Custom hook that works like `useEffect` but uses deep comparison on dependencies.
|
|
@@ -752,7 +753,7 @@ function useEqualMemoize(value) {
|
|
|
752
753
|
* @returns The result of the `useEffect` hook with memoized dependencies.
|
|
753
754
|
*/
|
|
754
755
|
function useEqualEffect(callback, dependencies) {
|
|
755
|
-
return useEffect(callback,
|
|
756
|
+
return useEffect(callback, [useEqualSignal(dependencies)]);
|
|
756
757
|
}
|
|
757
758
|
/**
|
|
758
759
|
* Custom hook that works like `useMemo` but uses deep comparison on dependencies.
|
|
@@ -762,7 +763,12 @@ function useEqualEffect(callback, dependencies) {
|
|
|
762
763
|
* @returns The result of the `useMemo` hook with memoized dependencies.
|
|
763
764
|
*/
|
|
764
765
|
function useEqualMemo(callback, dependencies) {
|
|
765
|
-
|
|
766
|
+
const signal = useEqualSignal(dependencies);
|
|
767
|
+
const callbackRef = useRef(callback);
|
|
768
|
+
callbackRef.current = callback;
|
|
769
|
+
return useMemo(() => {
|
|
770
|
+
return callbackRef.current();
|
|
771
|
+
}, [signal]);
|
|
766
772
|
}
|
|
767
773
|
/**
|
|
768
774
|
* Custom hook that works like `useCallback` but uses deep comparison on dependencies.
|
|
@@ -772,13 +778,9 @@ function useEqualMemo(callback, dependencies) {
|
|
|
772
778
|
* @returns The result of the `useCallback` hook with memoized dependencies.
|
|
773
779
|
*/
|
|
774
780
|
function useEqualCallback(callback, dependencies) {
|
|
775
|
-
return useCallback((...args) => callback(...args),
|
|
781
|
+
return useCallback((...args) => callback(...args), [useEqualSignal(dependencies)]);
|
|
776
782
|
}
|
|
777
|
-
|
|
778
|
-
//#endregion
|
|
779
|
-
//#region src/FaasDataWrapper.tsx
|
|
780
|
-
const fixedForwardRef = forwardRef;
|
|
781
|
-
const FaasDataWrapper = fixedForwardRef((props, ref) => {
|
|
783
|
+
const FaasDataWrapper = forwardRef((props, ref) => {
|
|
782
784
|
const requestOptions = {
|
|
783
785
|
...props.data !== void 0 ? { data: props.data } : {},
|
|
784
786
|
...props.setData ? { setData: props.setData } : {}
|
|
@@ -822,7 +824,6 @@ function withFaasData(Component, faasProps) {
|
|
|
822
824
|
children: /* @__PURE__ */ jsx(Component, { ...props })
|
|
823
825
|
});
|
|
824
826
|
}
|
|
825
|
-
|
|
826
827
|
//#endregion
|
|
827
828
|
//#region src/useFaas.tsx
|
|
828
829
|
/**
|
|
@@ -876,7 +877,8 @@ function useFaas(action, defaultParams, options = {}) {
|
|
|
876
877
|
const nextData = r.data;
|
|
877
878
|
setFails(0);
|
|
878
879
|
setError(null);
|
|
879
|
-
options.setData
|
|
880
|
+
if (options.setData) options.setData(nextData);
|
|
881
|
+
else localSetData(nextData);
|
|
880
882
|
setLoading(false);
|
|
881
883
|
for (const { resolve } of pendingReloadsRef.current.values()) resolve(nextData);
|
|
882
884
|
pendingReloadsRef.current.clear();
|
|
@@ -950,7 +952,6 @@ function useFaas(action, defaultParams, options = {}) {
|
|
|
950
952
|
setError
|
|
951
953
|
};
|
|
952
954
|
}
|
|
953
|
-
|
|
954
955
|
//#endregion
|
|
955
956
|
//#region src/client.tsx
|
|
956
957
|
const clients = {};
|
|
@@ -1011,7 +1012,6 @@ function getClient(host) {
|
|
|
1011
1012
|
}
|
|
1012
1013
|
return client;
|
|
1013
1014
|
}
|
|
1014
|
-
|
|
1015
1015
|
//#endregion
|
|
1016
1016
|
//#region src/constant.ts
|
|
1017
1017
|
/**
|
|
@@ -1022,7 +1022,6 @@ function useConstant(fn) {
|
|
|
1022
1022
|
if (!ref.current) ref.current = { v: fn() };
|
|
1023
1023
|
return ref.current.v;
|
|
1024
1024
|
}
|
|
1025
|
-
|
|
1026
1025
|
//#endregion
|
|
1027
1026
|
//#region src/ErrorBoundary.tsx
|
|
1028
1027
|
var ErrorBoundary = class extends Component {
|
|
@@ -1057,7 +1056,6 @@ var ErrorBoundary = class extends Component {
|
|
|
1057
1056
|
return this.props.children ?? null;
|
|
1058
1057
|
}
|
|
1059
1058
|
};
|
|
1060
|
-
|
|
1061
1059
|
//#endregion
|
|
1062
1060
|
//#region src/useStateRef.ts
|
|
1063
1061
|
/**
|
|
@@ -1094,7 +1092,6 @@ function useStateRef(initialValue) {
|
|
|
1094
1092
|
ref
|
|
1095
1093
|
];
|
|
1096
1094
|
}
|
|
1097
|
-
|
|
1098
1095
|
//#endregion
|
|
1099
1096
|
//#region src/splittingState.tsx
|
|
1100
1097
|
/**
|
|
@@ -1123,7 +1120,6 @@ function useSplittingState(initialStates) {
|
|
|
1123
1120
|
}
|
|
1124
1121
|
return states;
|
|
1125
1122
|
}
|
|
1126
|
-
|
|
1127
1123
|
//#endregion
|
|
1128
1124
|
//#region src/splittingContext.tsx
|
|
1129
1125
|
/**
|
|
@@ -1206,7 +1202,6 @@ function createSplittingContext(defaultValue) {
|
|
|
1206
1202
|
use
|
|
1207
1203
|
};
|
|
1208
1204
|
}
|
|
1209
|
-
|
|
1210
1205
|
//#endregion
|
|
1211
1206
|
//#region src/Form/context.tsx
|
|
1212
1207
|
const FormContext = createSplittingContext([
|
|
@@ -1225,7 +1220,6 @@ const FormContext = createSplittingContext([
|
|
|
1225
1220
|
]);
|
|
1226
1221
|
const FormContextProvider = FormContext.Provider;
|
|
1227
1222
|
const useFormContext = FormContext.use;
|
|
1228
|
-
|
|
1229
1223
|
//#endregion
|
|
1230
1224
|
//#region src/Form/Input.tsx
|
|
1231
1225
|
function processValue(input, rules) {
|
|
@@ -1258,7 +1252,6 @@ function FormInput({ name, rules, ...rest }) {
|
|
|
1258
1252
|
});
|
|
1259
1253
|
}
|
|
1260
1254
|
FormInput.displayName = "FormInput";
|
|
1261
|
-
|
|
1262
1255
|
//#endregion
|
|
1263
1256
|
//#region src/Form/Item.tsx
|
|
1264
1257
|
function FormItem(props) {
|
|
@@ -1275,7 +1268,6 @@ function FormItem(props) {
|
|
|
1275
1268
|
});
|
|
1276
1269
|
}
|
|
1277
1270
|
FormItem.displayName = "FormItem";
|
|
1278
|
-
|
|
1279
1271
|
//#endregion
|
|
1280
1272
|
//#region src/Form/Body.tsx
|
|
1281
1273
|
function FormBody() {
|
|
@@ -1283,7 +1275,6 @@ function FormBody() {
|
|
|
1283
1275
|
return items.map((item) => /* @__PURE__ */ jsx(FormItem, { ...item }, item.name));
|
|
1284
1276
|
}
|
|
1285
1277
|
FormBody.displayName = "FormBody";
|
|
1286
|
-
|
|
1287
1278
|
//#endregion
|
|
1288
1279
|
//#region src/Form/elements/Button.tsx
|
|
1289
1280
|
const FormButtonElement = forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsx("button", {
|
|
@@ -1295,7 +1286,6 @@ const FormButtonElement = forwardRef(({ children, submit, submitting, ...props }
|
|
|
1295
1286
|
children
|
|
1296
1287
|
}));
|
|
1297
1288
|
FormButtonElement.displayName = "FormButtonElement";
|
|
1298
|
-
|
|
1299
1289
|
//#endregion
|
|
1300
1290
|
//#region src/Form/elements/Input.tsx
|
|
1301
1291
|
const FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", {
|
|
@@ -1304,7 +1294,6 @@ const FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE_
|
|
|
1304
1294
|
ref
|
|
1305
1295
|
}));
|
|
1306
1296
|
FormInputElement.displayName = "FormInputElement";
|
|
1307
|
-
|
|
1308
1297
|
//#endregion
|
|
1309
1298
|
//#region src/Form/elements/Label.tsx
|
|
1310
1299
|
const FormLabelElement = ({ name, title, description, error, children }) => {
|
|
@@ -1319,7 +1308,6 @@ const FormLabelElement = ({ name, title, description, error, children }) => {
|
|
|
1319
1308
|
] });
|
|
1320
1309
|
};
|
|
1321
1310
|
FormLabelElement.displayName = "FormLabelElement";
|
|
1322
|
-
|
|
1323
1311
|
//#endregion
|
|
1324
1312
|
//#region src/Form/elements/index.ts
|
|
1325
1313
|
const FormDefaultElements = {
|
|
@@ -1327,7 +1315,6 @@ const FormDefaultElements = {
|
|
|
1327
1315
|
Input: FormInputElement,
|
|
1328
1316
|
Button: FormButtonElement
|
|
1329
1317
|
};
|
|
1330
|
-
|
|
1331
1318
|
//#endregion
|
|
1332
1319
|
//#region src/Form/rules.ts
|
|
1333
1320
|
/**
|
|
@@ -1365,42 +1352,36 @@ async function validValues(rules, items, values, lang) {
|
|
|
1365
1352
|
}
|
|
1366
1353
|
return errors;
|
|
1367
1354
|
}
|
|
1368
|
-
|
|
1369
1355
|
//#endregion
|
|
1370
1356
|
//#region src/Form/Footer.tsx
|
|
1371
1357
|
function FormFooter() {
|
|
1372
1358
|
const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
|
|
1373
|
-
const
|
|
1374
|
-
|
|
1375
|
-
setErrors({});
|
|
1376
|
-
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1377
|
-
if (Object.keys(errors).length) {
|
|
1378
|
-
setErrors(errors);
|
|
1379
|
-
setSubmitting(false);
|
|
1380
|
-
return;
|
|
1381
|
-
}
|
|
1382
|
-
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1383
|
-
}, [
|
|
1384
|
-
setSubmitting,
|
|
1385
|
-
setErrors,
|
|
1386
|
-
rules,
|
|
1387
|
-
items,
|
|
1388
|
-
lang,
|
|
1389
|
-
onSubmit
|
|
1390
|
-
]);
|
|
1391
|
-
return useMemo(() => /* @__PURE__ */ jsx(Elements.Button, {
|
|
1359
|
+
const Button = Elements.Button;
|
|
1360
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
1392
1361
|
submitting,
|
|
1393
|
-
submit:
|
|
1362
|
+
submit: useCallback(async () => {
|
|
1363
|
+
setSubmitting(true);
|
|
1364
|
+
setErrors({});
|
|
1365
|
+
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1366
|
+
if (Object.keys(errors).length) {
|
|
1367
|
+
setErrors(errors);
|
|
1368
|
+
setSubmitting(false);
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1372
|
+
}, [
|
|
1373
|
+
setSubmitting,
|
|
1374
|
+
setErrors,
|
|
1375
|
+
rules,
|
|
1376
|
+
items,
|
|
1377
|
+
valuesRef,
|
|
1378
|
+
lang,
|
|
1379
|
+
onSubmit
|
|
1380
|
+
]),
|
|
1394
1381
|
children: lang.submit
|
|
1395
|
-
})
|
|
1396
|
-
submitting,
|
|
1397
|
-
handleSubmit,
|
|
1398
|
-
lang.submit,
|
|
1399
|
-
Elements.Button
|
|
1400
|
-
]);
|
|
1382
|
+
});
|
|
1401
1383
|
}
|
|
1402
1384
|
FormFooter.displayName = "FormFooter";
|
|
1403
|
-
|
|
1404
1385
|
//#endregion
|
|
1405
1386
|
//#region src/Form/lang.ts
|
|
1406
1387
|
const FormDefaultLang = {
|
|
@@ -1409,7 +1390,6 @@ const FormDefaultLang = {
|
|
|
1409
1390
|
string: "This field must be a string",
|
|
1410
1391
|
number: "This field must be a number"
|
|
1411
1392
|
};
|
|
1412
|
-
|
|
1413
1393
|
//#endregion
|
|
1414
1394
|
//#region src/Form/Container.tsx
|
|
1415
1395
|
function mergeValues(items, defaultValues = {}) {
|
|
@@ -1469,7 +1449,6 @@ function FormContainer({ defaultValues, Elements, rules, lang, items, ...props }
|
|
|
1469
1449
|
});
|
|
1470
1450
|
}
|
|
1471
1451
|
FormContainer.displayName = "FormContainer";
|
|
1472
|
-
|
|
1473
1452
|
//#endregion
|
|
1474
1453
|
//#region src/OptionalWrapper.tsx
|
|
1475
1454
|
/**
|
|
@@ -1498,7 +1477,6 @@ function OptionalWrapper({ condition, Wrapper, wrapperProps, children }) {
|
|
|
1498
1477
|
return children;
|
|
1499
1478
|
}
|
|
1500
1479
|
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1501
|
-
|
|
1502
1480
|
//#endregion
|
|
1503
1481
|
//#region src/useFaasStream.tsx
|
|
1504
1482
|
/**
|
|
@@ -1644,7 +1622,6 @@ function useFaasStream(action, defaultParams, options = {}) {
|
|
|
1644
1622
|
setError
|
|
1645
1623
|
};
|
|
1646
1624
|
}
|
|
1647
|
-
|
|
1648
1625
|
//#endregion
|
|
1649
1626
|
//#region src/usePrevious.ts
|
|
1650
1627
|
/**
|
|
@@ -1661,6 +1638,5 @@ function usePrevious(value) {
|
|
|
1661
1638
|
});
|
|
1662
1639
|
return ref.current;
|
|
1663
1640
|
}
|
|
1664
|
-
|
|
1665
1641
|
//#endregion
|
|
1666
|
-
export { ErrorBoundary, FaasBrowserClient, FaasDataWrapper, FaasReactClient, FormContainer as Form, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormInput, FormItem, OptionalWrapper, Response, ResponseError, createSplittingContext, equal, faas, generateId, getClient, setMock, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
|
1642
|
+
export { ErrorBoundary, FaasBrowserClient, FaasDataWrapper, FaasReactClient, FormContainer as Form, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormInput, FormItem, OptionalWrapper, Response, ResponseError, createSplittingContext, equal, faas, generateId, getClient, setMock, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/react",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.15",
|
|
4
4
|
"homepage": "https://faasjs.com/doc/react/",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/faasjs/faasjs/issues"
|
|
@@ -26,16 +26,13 @@
|
|
|
26
26
|
"require": "./dist/index.cjs"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
|
-
"scripts": {
|
|
30
|
-
"build": "tsdown src/index.ts --config ../../tsdown.config.ts --external react --dts.eager --no-sourcemap --no-dts.sourcemap"
|
|
31
|
-
},
|
|
32
29
|
"devDependencies": {
|
|
33
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
30
|
+
"@faasjs/types": ">=8.0.0-beta.15",
|
|
34
31
|
"@types/react": "^19.0.0",
|
|
35
32
|
"react": "^19.0.0"
|
|
36
33
|
},
|
|
37
34
|
"peerDependencies": {
|
|
38
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
35
|
+
"@faasjs/types": ">=8.0.0-beta.15"
|
|
39
36
|
},
|
|
40
37
|
"engines": {
|
|
41
38
|
"node": ">=24.0.0",
|