@faasjs/react 8.0.0-beta.16 → 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 +56 -309
- package/dist/index.d.ts +2 -216
- package/dist/index.mjs +57 -301
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -6,9 +6,6 @@
|
|
|
6
6
|
- [equal](functions/equal.md)
|
|
7
7
|
- [faas](functions/faas.md)
|
|
8
8
|
- [FaasReactClient](functions/FaasReactClient.md)
|
|
9
|
-
- [Form](functions/Form.md)
|
|
10
|
-
- [FormInput](functions/FormInput.md)
|
|
11
|
-
- [FormItem](functions/FormItem.md)
|
|
12
9
|
- [generateId](functions/generateId.md)
|
|
13
10
|
- [getClient](functions/getClient.md)
|
|
14
11
|
- [OptionalWrapper](functions/OptionalWrapper.md)
|
|
@@ -23,7 +20,6 @@
|
|
|
23
20
|
- [usePrevious](functions/usePrevious.md)
|
|
24
21
|
- [useSplittingState](functions/useSplittingState.md)
|
|
25
22
|
- [useStateRef](functions/useStateRef.md)
|
|
26
|
-
- [validValues](functions/validValues.md)
|
|
27
23
|
- [withFaasData](functions/withFaasData.md)
|
|
28
24
|
|
|
29
25
|
## Classes
|
|
@@ -51,22 +47,6 @@
|
|
|
51
47
|
- [FaasParams](type-aliases/FaasParams.md)
|
|
52
48
|
- [FaasReactClientInstance](type-aliases/FaasReactClientInstance.md)
|
|
53
49
|
- [FaasReactClientOptions](type-aliases/FaasReactClientOptions.md)
|
|
54
|
-
- [FormButtonElementProps](type-aliases/FormButtonElementProps.md)
|
|
55
|
-
- [FormContextProps](type-aliases/FormContextProps.md)
|
|
56
|
-
- [FormDefaultRulesOptions](type-aliases/FormDefaultRulesOptions.md)
|
|
57
|
-
- [FormElementTypes](type-aliases/FormElementTypes.md)
|
|
58
|
-
- [FormInputElementProps](type-aliases/FormInputElementProps.md)
|
|
59
|
-
- [FormInputProps](type-aliases/FormInputProps.md)
|
|
60
|
-
- [FormItemName](type-aliases/FormItemName.md)
|
|
61
|
-
- [FormItemProps](type-aliases/FormItemProps.md)
|
|
62
|
-
- [FormLabelElementProps](type-aliases/FormLabelElementProps.md)
|
|
63
|
-
- [FormLang](type-aliases/FormLang.md)
|
|
64
|
-
- [FormProps](type-aliases/FormProps.md)
|
|
65
|
-
- [FormRule](type-aliases/FormRule.md)
|
|
66
|
-
- [FormRules](type-aliases/FormRules.md)
|
|
67
|
-
- [InferFormInputProps](type-aliases/InferFormInputProps.md)
|
|
68
|
-
- [InferFormRulesOptions](type-aliases/InferFormRulesOptions.md)
|
|
69
|
-
- [InferRuleOption](type-aliases/InferRuleOption.md)
|
|
70
50
|
- [MockHandler](type-aliases/MockHandler.md)
|
|
71
51
|
- [OnError](type-aliases/OnError.md)
|
|
72
52
|
- [OptionalWrapperProps](type-aliases/OptionalWrapperProps.md)
|
|
@@ -83,8 +63,3 @@
|
|
|
83
63
|
## Variables
|
|
84
64
|
|
|
85
65
|
- [FaasDataWrapper](variables/FaasDataWrapper.md)
|
|
86
|
-
- [FormContextProvider](variables/FormContextProvider.md)
|
|
87
|
-
- [FormDefaultElements](variables/FormDefaultElements.md)
|
|
88
|
-
- [FormDefaultLang](variables/FormDefaultLang.md)
|
|
89
|
-
- [FormDefaultRules](variables/FormDefaultRules.md)
|
|
90
|
-
- [useFormContext](variables/useFormContext.md)
|
package/dist/index.cjs
CHANGED
|
@@ -1080,43 +1080,33 @@ var ErrorBoundary = class extends react.Component {
|
|
|
1080
1080
|
}
|
|
1081
1081
|
};
|
|
1082
1082
|
//#endregion
|
|
1083
|
-
//#region src/
|
|
1083
|
+
//#region src/OptionalWrapper.tsx
|
|
1084
1084
|
/**
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
* @template T - The type of the value.
|
|
1088
|
-
* @param initialValue - Initial state value. When omitted, state starts as `null`.
|
|
1089
|
-
* @returns Tuple containing the current state, the state setter, and a ref that always points at the latest state.
|
|
1085
|
+
* A wrapper component that conditionally wraps its children with a provided wrapper component.
|
|
1090
1086
|
*
|
|
1091
1087
|
* @example
|
|
1092
1088
|
* ```tsx
|
|
1093
|
-
* import {
|
|
1089
|
+
* import { OptionalWrapper } from '@faasjs/react'
|
|
1094
1090
|
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1091
|
+
* const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
1092
|
+
* <div className='wrapper'>{children}</div>
|
|
1093
|
+
* )
|
|
1097
1094
|
*
|
|
1098
|
-
*
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1102
|
-
*
|
|
1103
|
-
* </div>
|
|
1104
|
-
* )
|
|
1105
|
-
* }
|
|
1095
|
+
* const App = () => (
|
|
1096
|
+
* <OptionalWrapper condition={true} Wrapper={Wrapper}>
|
|
1097
|
+
* <span>Test</span>
|
|
1098
|
+
* </OptionalWrapper>
|
|
1099
|
+
* )
|
|
1106
1100
|
* ```
|
|
1107
1101
|
*/
|
|
1108
|
-
function
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
return [
|
|
1115
|
-
state,
|
|
1116
|
-
setState,
|
|
1117
|
-
ref
|
|
1118
|
-
];
|
|
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;
|
|
1119
1108
|
}
|
|
1109
|
+
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1120
1110
|
//#endregion
|
|
1121
1111
|
//#region src/splittingState.tsx
|
|
1122
1112
|
/**
|
|
@@ -1229,278 +1219,6 @@ function createSplittingContext(defaultValue) {
|
|
|
1229
1219
|
};
|
|
1230
1220
|
}
|
|
1231
1221
|
//#endregion
|
|
1232
|
-
//#region src/Form/context.tsx
|
|
1233
|
-
const FormContext = createSplittingContext([
|
|
1234
|
-
"items",
|
|
1235
|
-
"onSubmit",
|
|
1236
|
-
"Elements",
|
|
1237
|
-
"lang",
|
|
1238
|
-
"rules",
|
|
1239
|
-
"submitting",
|
|
1240
|
-
"setSubmitting",
|
|
1241
|
-
"values",
|
|
1242
|
-
"setValues",
|
|
1243
|
-
"errors",
|
|
1244
|
-
"setErrors",
|
|
1245
|
-
"valuesRef"
|
|
1246
|
-
]);
|
|
1247
|
-
const FormContextProvider = FormContext.Provider;
|
|
1248
|
-
const useFormContext = FormContext.use;
|
|
1249
|
-
//#endregion
|
|
1250
|
-
//#region src/Form/Input.tsx
|
|
1251
|
-
function processValue(input, rules) {
|
|
1252
|
-
switch (rules?.type) {
|
|
1253
|
-
case "number": return Number(input);
|
|
1254
|
-
case "string": return String(input);
|
|
1255
|
-
default: return input;
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
function FormInput({ name, rules, ...rest }) {
|
|
1259
|
-
const { Elements, values, setValues } = useFormContext();
|
|
1260
|
-
const value = values?.[name];
|
|
1261
|
-
if (rest.Input) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(rest.Input, {
|
|
1262
|
-
name,
|
|
1263
|
-
value,
|
|
1264
|
-
onChange: (v) => setValues((prev) => ({
|
|
1265
|
-
...prev,
|
|
1266
|
-
[name]: processValue(v, rules)
|
|
1267
|
-
})),
|
|
1268
|
-
...rest.props
|
|
1269
|
-
});
|
|
1270
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Elements.Input, {
|
|
1271
|
-
name,
|
|
1272
|
-
value,
|
|
1273
|
-
onChange: (v) => setValues((prev) => ({
|
|
1274
|
-
...prev,
|
|
1275
|
-
[name]: processValue(v, rules)
|
|
1276
|
-
})),
|
|
1277
|
-
...rest.props
|
|
1278
|
-
});
|
|
1279
|
-
}
|
|
1280
|
-
FormInput.displayName = "FormInput";
|
|
1281
|
-
//#endregion
|
|
1282
|
-
//#region src/Form/Item.tsx
|
|
1283
|
-
function FormItem(props) {
|
|
1284
|
-
const { Elements, errors } = useFormContext();
|
|
1285
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(props.label?.Label ?? Elements.Label, {
|
|
1286
|
-
name: props.name,
|
|
1287
|
-
...props.label,
|
|
1288
|
-
error: errors[props.name],
|
|
1289
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormInput, {
|
|
1290
|
-
name: props.name,
|
|
1291
|
-
...props.input,
|
|
1292
|
-
...props.rules ? { rules: props.rules } : {}
|
|
1293
|
-
})
|
|
1294
|
-
});
|
|
1295
|
-
}
|
|
1296
|
-
FormItem.displayName = "FormItem";
|
|
1297
|
-
//#endregion
|
|
1298
|
-
//#region src/Form/Body.tsx
|
|
1299
|
-
function FormBody() {
|
|
1300
|
-
const { items } = useFormContext();
|
|
1301
|
-
return items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormItem, { ...item }, item.name));
|
|
1302
|
-
}
|
|
1303
|
-
FormBody.displayName = "FormBody";
|
|
1304
|
-
//#endregion
|
|
1305
|
-
//#region src/Form/elements/Button.tsx
|
|
1306
|
-
const FormButtonElement = (0, react.forwardRef)(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1307
|
-
type: "button",
|
|
1308
|
-
disabled: submitting,
|
|
1309
|
-
onClick: submit,
|
|
1310
|
-
...props,
|
|
1311
|
-
ref,
|
|
1312
|
-
children
|
|
1313
|
-
}));
|
|
1314
|
-
FormButtonElement.displayName = "FormButtonElement";
|
|
1315
|
-
//#endregion
|
|
1316
|
-
//#region src/Form/elements/Input.tsx
|
|
1317
|
-
const FormInputElement = (0, react.forwardRef)(({ onChange, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1318
|
-
...props,
|
|
1319
|
-
onChange: (e) => onChange(e.target.value),
|
|
1320
|
-
ref
|
|
1321
|
-
}));
|
|
1322
|
-
FormInputElement.displayName = "FormInputElement";
|
|
1323
|
-
//#endregion
|
|
1324
|
-
//#region src/Form/elements/Label.tsx
|
|
1325
|
-
const FormLabelElement = ({ name, title, description, error, children }) => {
|
|
1326
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
|
|
1327
|
-
title ?? name,
|
|
1328
|
-
children,
|
|
1329
|
-
description,
|
|
1330
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1331
|
-
style: { color: "red" },
|
|
1332
|
-
children: error.message
|
|
1333
|
-
})
|
|
1334
|
-
] });
|
|
1335
|
-
};
|
|
1336
|
-
FormLabelElement.displayName = "FormLabelElement";
|
|
1337
|
-
//#endregion
|
|
1338
|
-
//#region src/Form/elements/index.ts
|
|
1339
|
-
const FormDefaultElements = {
|
|
1340
|
-
Label: FormLabelElement,
|
|
1341
|
-
Input: FormInputElement,
|
|
1342
|
-
Button: FormButtonElement
|
|
1343
|
-
};
|
|
1344
|
-
//#endregion
|
|
1345
|
-
//#region src/Form/rules.ts
|
|
1346
|
-
/**
|
|
1347
|
-
* Default validation rules for a form.
|
|
1348
|
-
*/
|
|
1349
|
-
const FormDefaultRules = {
|
|
1350
|
-
required: async (value, _, lang) => {
|
|
1351
|
-
if (value === null || value === void 0 || value === "" || Number.isNaN(value)) throw Error(lang?.required);
|
|
1352
|
-
},
|
|
1353
|
-
type: async (value, options, lang) => {
|
|
1354
|
-
switch (options) {
|
|
1355
|
-
case "string":
|
|
1356
|
-
if (typeof value !== "string") throw Error(lang?.string);
|
|
1357
|
-
break;
|
|
1358
|
-
case "number":
|
|
1359
|
-
if (Number.isNaN(Number(value))) throw Error(lang?.number);
|
|
1360
|
-
break;
|
|
1361
|
-
}
|
|
1362
|
-
},
|
|
1363
|
-
custom: async (value, options) => {
|
|
1364
|
-
return options(value);
|
|
1365
|
-
}
|
|
1366
|
-
};
|
|
1367
|
-
async function validValues(rules, items, values, lang) {
|
|
1368
|
-
const errors = {};
|
|
1369
|
-
for (const item of items) {
|
|
1370
|
-
const value = values[item.name];
|
|
1371
|
-
const rulesOptions = item.rules;
|
|
1372
|
-
if (rulesOptions) for (const [name, options] of Object.entries(rulesOptions)) try {
|
|
1373
|
-
await rules[name](value, options, lang);
|
|
1374
|
-
} catch (error) {
|
|
1375
|
-
errors[item.name] = error;
|
|
1376
|
-
break;
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
return errors;
|
|
1380
|
-
}
|
|
1381
|
-
//#endregion
|
|
1382
|
-
//#region src/Form/Footer.tsx
|
|
1383
|
-
function FormFooter() {
|
|
1384
|
-
const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
|
|
1385
|
-
const Button = Elements.Button;
|
|
1386
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
1387
|
-
submitting,
|
|
1388
|
-
submit: (0, react.useCallback)(async () => {
|
|
1389
|
-
setSubmitting(true);
|
|
1390
|
-
setErrors({});
|
|
1391
|
-
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1392
|
-
if (Object.keys(errors).length) {
|
|
1393
|
-
setErrors(errors);
|
|
1394
|
-
setSubmitting(false);
|
|
1395
|
-
return;
|
|
1396
|
-
}
|
|
1397
|
-
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1398
|
-
}, [
|
|
1399
|
-
setSubmitting,
|
|
1400
|
-
setErrors,
|
|
1401
|
-
rules,
|
|
1402
|
-
items,
|
|
1403
|
-
valuesRef,
|
|
1404
|
-
lang,
|
|
1405
|
-
onSubmit
|
|
1406
|
-
]),
|
|
1407
|
-
children: lang.submit
|
|
1408
|
-
});
|
|
1409
|
-
}
|
|
1410
|
-
FormFooter.displayName = "FormFooter";
|
|
1411
|
-
//#endregion
|
|
1412
|
-
//#region src/Form/lang.ts
|
|
1413
|
-
const FormDefaultLang = {
|
|
1414
|
-
submit: "Submit",
|
|
1415
|
-
required: "This field is required",
|
|
1416
|
-
string: "This field must be a string",
|
|
1417
|
-
number: "This field must be a number"
|
|
1418
|
-
};
|
|
1419
|
-
//#endregion
|
|
1420
|
-
//#region src/Form/Container.tsx
|
|
1421
|
-
function mergeValues(items, defaultValues = {}) {
|
|
1422
|
-
const values = {};
|
|
1423
|
-
for (const item of items) values[item.name] = defaultValues[item.name] ?? "";
|
|
1424
|
-
return values;
|
|
1425
|
-
}
|
|
1426
|
-
/**
|
|
1427
|
-
* Render a form with context, default elements, and validation state.
|
|
1428
|
-
*
|
|
1429
|
-
* `FormContainer` merges provided elements, language strings, and rules with
|
|
1430
|
-
* the package defaults, then exposes them through form context.
|
|
1431
|
-
*
|
|
1432
|
-
* @template Values - The type of form values, defaults to Record<string, any>.
|
|
1433
|
-
* @template FormElements - The type of form elements, defaults to FormElementTypes.
|
|
1434
|
-
* @template Rules - The type of form rules, defaults to FormDefaultRules.
|
|
1435
|
-
* @param props - Form items and optional overrides for defaults, language, rules, and submit behavior.
|
|
1436
|
-
* @returns React form container with shared form context.
|
|
1437
|
-
*
|
|
1438
|
-
* @example
|
|
1439
|
-
* ```tsx
|
|
1440
|
-
* import { Form } from '@faasjs/react'
|
|
1441
|
-
*
|
|
1442
|
-
* function MyForm() {
|
|
1443
|
-
* return (
|
|
1444
|
-
* <Form
|
|
1445
|
-
* items={[
|
|
1446
|
-
* { name: 'name' },
|
|
1447
|
-
* ]}
|
|
1448
|
-
* />
|
|
1449
|
-
* )
|
|
1450
|
-
* }
|
|
1451
|
-
* ```
|
|
1452
|
-
*/
|
|
1453
|
-
function FormContainer({ defaultValues, Elements, rules, lang, items, ...props }) {
|
|
1454
|
-
const [values, setValues, valuesRef] = useStateRef(mergeValues(items, defaultValues));
|
|
1455
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(FormContextProvider, {
|
|
1456
|
-
initializeStates: {
|
|
1457
|
-
errors: {},
|
|
1458
|
-
submitting: false
|
|
1459
|
-
},
|
|
1460
|
-
value: {
|
|
1461
|
-
Elements: Object.assign(FormDefaultElements, Elements),
|
|
1462
|
-
lang: Object.assign(FormDefaultLang, lang),
|
|
1463
|
-
rules: Object.assign(FormDefaultRules, rules),
|
|
1464
|
-
items,
|
|
1465
|
-
values,
|
|
1466
|
-
setValues,
|
|
1467
|
-
valuesRef,
|
|
1468
|
-
...props
|
|
1469
|
-
},
|
|
1470
|
-
memo: true,
|
|
1471
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormBody, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormFooter, {})]
|
|
1472
|
-
});
|
|
1473
|
-
}
|
|
1474
|
-
FormContainer.displayName = "FormContainer";
|
|
1475
|
-
//#endregion
|
|
1476
|
-
//#region src/OptionalWrapper.tsx
|
|
1477
|
-
/**
|
|
1478
|
-
* A wrapper component that conditionally wraps its children with a provided wrapper component.
|
|
1479
|
-
*
|
|
1480
|
-
* @example
|
|
1481
|
-
* ```tsx
|
|
1482
|
-
* import { OptionalWrapper } from '@faasjs/react'
|
|
1483
|
-
*
|
|
1484
|
-
* const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
1485
|
-
* <div className='wrapper'>{children}</div>
|
|
1486
|
-
* )
|
|
1487
|
-
*
|
|
1488
|
-
* const App = () => (
|
|
1489
|
-
* <OptionalWrapper condition={true} Wrapper={Wrapper}>
|
|
1490
|
-
* <span>Test</span>
|
|
1491
|
-
* </OptionalWrapper>
|
|
1492
|
-
* )
|
|
1493
|
-
* ```
|
|
1494
|
-
*/
|
|
1495
|
-
function OptionalWrapper({ condition, Wrapper, wrapperProps, children }) {
|
|
1496
|
-
if (condition) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Wrapper, {
|
|
1497
|
-
...wrapperProps,
|
|
1498
|
-
children
|
|
1499
|
-
});
|
|
1500
|
-
return children;
|
|
1501
|
-
}
|
|
1502
|
-
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1503
|
-
//#endregion
|
|
1504
1222
|
//#region src/useFaasStream.tsx
|
|
1505
1223
|
/**
|
|
1506
1224
|
* Stream a FaasJS response into React state.
|
|
@@ -1669,17 +1387,48 @@ function usePrevious(value) {
|
|
|
1669
1387
|
return ref.current;
|
|
1670
1388
|
}
|
|
1671
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
|
|
1672
1428
|
exports.ErrorBoundary = ErrorBoundary;
|
|
1673
1429
|
exports.FaasBrowserClient = FaasBrowserClient;
|
|
1674
1430
|
exports.FaasDataWrapper = FaasDataWrapper;
|
|
1675
1431
|
exports.FaasReactClient = FaasReactClient;
|
|
1676
|
-
exports.Form = FormContainer;
|
|
1677
|
-
exports.FormContextProvider = FormContextProvider;
|
|
1678
|
-
exports.FormDefaultElements = FormDefaultElements;
|
|
1679
|
-
exports.FormDefaultLang = FormDefaultLang;
|
|
1680
|
-
exports.FormDefaultRules = FormDefaultRules;
|
|
1681
|
-
exports.FormInput = FormInput;
|
|
1682
|
-
exports.FormItem = FormItem;
|
|
1683
1432
|
exports.OptionalWrapper = OptionalWrapper;
|
|
1684
1433
|
exports.Response = Response;
|
|
1685
1434
|
exports.ResponseError = ResponseError;
|
|
@@ -1696,9 +1445,7 @@ exports.useEqualMemo = useEqualMemo;
|
|
|
1696
1445
|
exports.useEqualMemoize = useEqualMemoize;
|
|
1697
1446
|
exports.useFaas = useFaas;
|
|
1698
1447
|
exports.useFaasStream = useFaasStream;
|
|
1699
|
-
exports.useFormContext = useFormContext;
|
|
1700
1448
|
exports.usePrevious = usePrevious;
|
|
1701
1449
|
exports.useSplittingState = useSplittingState;
|
|
1702
1450
|
exports.useStateRef = useStateRef;
|
|
1703
|
-
exports.validValues = validValues;
|
|
1704
1451
|
exports.withFaasData = withFaasData;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FaasAction, FaasAction as FaasAction$1, FaasActionUnionType, FaasActionUnionType as FaasActionUnionType$1, FaasData, FaasData as FaasData$1, FaasParams, FaasParams as FaasParams$1 } from "@faasjs/types";
|
|
2
2
|
import * as react from "react";
|
|
3
|
-
import { Component, ComponentProps, ComponentType, Dispatch, ErrorInfo, JSX,
|
|
3
|
+
import { Component, ComponentProps, ComponentType, Dispatch, ErrorInfo, JSX, ReactElement, ReactNode, RefObject, SetStateAction } from "react";
|
|
4
4
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
//#region src/generateId.d.ts
|
|
@@ -1041,220 +1041,6 @@ declare function useEqualMemo<T>(callback: () => T, dependencies: any[]): T;
|
|
|
1041
1041
|
*/
|
|
1042
1042
|
declare function useEqualCallback<T extends (...args: any[]) => any>(callback: T, dependencies: any[]): T;
|
|
1043
1043
|
//#endregion
|
|
1044
|
-
//#region src/Form/elements/Button.d.ts
|
|
1045
|
-
/**
|
|
1046
|
-
* Props for the FormButtonElement component.
|
|
1047
|
-
*
|
|
1048
|
-
* @property {React.ReactNode} [children] - The content to be displayed inside the button.
|
|
1049
|
-
* @property {boolean} disabled - Indicates whether the button is disabled.
|
|
1050
|
-
* @property {() => Promise<void>} submit - A function to be called when the button is clicked, which returns a promise.
|
|
1051
|
-
*/
|
|
1052
|
-
type FormButtonElementProps = {
|
|
1053
|
-
children?: React.ReactNode;
|
|
1054
|
-
submitting: boolean;
|
|
1055
|
-
submit: () => Promise<void>;
|
|
1056
|
-
};
|
|
1057
|
-
//#endregion
|
|
1058
|
-
//#region src/Form/elements/Input.d.ts
|
|
1059
|
-
/**
|
|
1060
|
-
* Props for the Form Input Element component.
|
|
1061
|
-
*
|
|
1062
|
-
* @property {string} name - The name of the input element.
|
|
1063
|
-
* @property {any} value - The current value of the input element.
|
|
1064
|
-
* @property {(value: any) => void} onChange - Callback function to handle changes to the input value.
|
|
1065
|
-
*/
|
|
1066
|
-
type FormInputElementProps = {
|
|
1067
|
-
name: string;
|
|
1068
|
-
value: any;
|
|
1069
|
-
onChange: (value: any) => void;
|
|
1070
|
-
};
|
|
1071
|
-
//#endregion
|
|
1072
|
-
//#region src/Form/elements/Label.d.ts
|
|
1073
|
-
/**
|
|
1074
|
-
* Props for the FormLabelElement component.
|
|
1075
|
-
*
|
|
1076
|
-
* @typedef {Object} FormLabelElementProps
|
|
1077
|
-
* @property {string} name - The name of the form element.
|
|
1078
|
-
* @property {ReactNode} [title] - Optional title for the form element.
|
|
1079
|
-
* @property {ReactNode} [description] - Optional description for the form element.
|
|
1080
|
-
* @property {Error} [error] - Optional error associated with the form element.
|
|
1081
|
-
* @property {ReactNode} children - The child elements, typically an input element.
|
|
1082
|
-
*/
|
|
1083
|
-
type FormLabelElementProps = {
|
|
1084
|
-
name: string;
|
|
1085
|
-
title?: ReactNode;
|
|
1086
|
-
description?: ReactNode;
|
|
1087
|
-
error?: Error; /** as Input element */
|
|
1088
|
-
children: ReactNode;
|
|
1089
|
-
};
|
|
1090
|
-
//#endregion
|
|
1091
|
-
//#region src/Form/elements/index.d.ts
|
|
1092
|
-
/**
|
|
1093
|
-
* Represents the types of form elements used in the form.
|
|
1094
|
-
*
|
|
1095
|
-
* @typedef {Object} FormElementTypes
|
|
1096
|
-
* @property {ComponentType<FormLabelElementProps>} Label - The component type for the form label element.
|
|
1097
|
-
* @property {ComponentType<FormInputElementProps>} Input - The component type for the form input element.
|
|
1098
|
-
* @property {ComponentType<FormButtonElementProps>} Button - The component type for the form button element.
|
|
1099
|
-
*/
|
|
1100
|
-
type FormElementTypes = {
|
|
1101
|
-
Label: ComponentType<FormLabelElementProps>;
|
|
1102
|
-
Input: ComponentType<FormInputElementProps>;
|
|
1103
|
-
Button: ComponentType<FormButtonElementProps>;
|
|
1104
|
-
};
|
|
1105
|
-
declare const FormDefaultElements: FormElementTypes;
|
|
1106
|
-
//#endregion
|
|
1107
|
-
//#region src/Form/lang.d.ts
|
|
1108
|
-
declare const FormDefaultLang: {
|
|
1109
|
-
submit: string;
|
|
1110
|
-
required: string;
|
|
1111
|
-
string: string;
|
|
1112
|
-
number: string;
|
|
1113
|
-
};
|
|
1114
|
-
type FormLang = typeof FormDefaultLang;
|
|
1115
|
-
//#endregion
|
|
1116
|
-
//#region src/Form/rules.d.ts
|
|
1117
|
-
/**
|
|
1118
|
-
* A type representing a form validation rule.
|
|
1119
|
-
*
|
|
1120
|
-
* @template Options - The type of the options that can be passed to the rule.
|
|
1121
|
-
*
|
|
1122
|
-
* @param value - The value to be validated.
|
|
1123
|
-
* @param options - Optional. Additional options that can be used in the validation.
|
|
1124
|
-
* @param lang - Optional. The language settings that can be used in the validation.
|
|
1125
|
-
*
|
|
1126
|
-
* @returns A promise that resolves if the validation is successful, or rejects with an error if the validation fails.
|
|
1127
|
-
*
|
|
1128
|
-
* @example
|
|
1129
|
-
* ```ts
|
|
1130
|
-
* async function required(value: any, options: boolean, lang?: FormLang) {
|
|
1131
|
-
* if (value === null || value === undefined || value === '' || Number.isNaN(value))
|
|
1132
|
-
* throw Error(lang?.required)
|
|
1133
|
-
* }
|
|
1134
|
-
* ```
|
|
1135
|
-
*/
|
|
1136
|
-
type FormRule<Options = any> = (value: any, options?: Options, lang?: FormLang) => Promise<void>;
|
|
1137
|
-
type InferRuleOption<T> = T extends ((value: any, options: infer O, lang?: FormLang) => Promise<void>) ? O : never;
|
|
1138
|
-
/**
|
|
1139
|
-
* A type representing a set of form validation rules.
|
|
1140
|
-
*
|
|
1141
|
-
* @typedef {Record<string, FormRule>} FormRules
|
|
1142
|
-
*
|
|
1143
|
-
* Each key in the record represents the name of a form field, and the corresponding value is a `FormRule` object that defines the validation rules for that field.
|
|
1144
|
-
*/
|
|
1145
|
-
type FormRules = Record<string, FormRule>;
|
|
1146
|
-
type InferFormRulesOptions<T> = { [K in keyof T]: InferRuleOption<T[K]> };
|
|
1147
|
-
/**
|
|
1148
|
-
* Default validation rules for a form.
|
|
1149
|
-
*/
|
|
1150
|
-
declare const FormDefaultRules: FormRules;
|
|
1151
|
-
type FormDefaultRulesOptions = InferFormRulesOptions<typeof FormDefaultRules>;
|
|
1152
|
-
declare function validValues(rules: FormRules, items: FormItemProps[], values: Record<string, any>, lang: FormLang): Promise<Record<string, Error>>;
|
|
1153
|
-
//#endregion
|
|
1154
|
-
//#region src/Form/Input.d.ts
|
|
1155
|
-
type InferFormInputProps<T extends ComponentType<FormInputElementProps> | JSXElementConstructor<any>> = T extends ComponentType<FormInputElementProps> ? Omit<ComponentProps<T>, 'name' | 'value' | 'onChange'> : Omit<ComponentProps<T>, 'name' | 'value'>;
|
|
1156
|
-
type FormInputProps<FormElements extends FormElementTypes = FormElementTypes> = {
|
|
1157
|
-
Input?: ComponentType<FormInputElementProps>;
|
|
1158
|
-
props?: InferFormInputProps<FormElements['Input']>;
|
|
1159
|
-
};
|
|
1160
|
-
declare function FormInput({
|
|
1161
|
-
name,
|
|
1162
|
-
rules,
|
|
1163
|
-
...rest
|
|
1164
|
-
}: FormInputProps & {
|
|
1165
|
-
name: string;
|
|
1166
|
-
rules?: FormDefaultRulesOptions;
|
|
1167
|
-
}): react_jsx_runtime0.JSX.Element;
|
|
1168
|
-
declare namespace FormInput {
|
|
1169
|
-
var displayName: string;
|
|
1170
|
-
}
|
|
1171
|
-
//#endregion
|
|
1172
|
-
//#region src/Form/Item.d.ts
|
|
1173
|
-
type FormItemName = string;
|
|
1174
|
-
type FormItemProps<FormElements extends FormElementTypes = FormElementTypes, FormRulesOptions extends Record<string, any> = FormDefaultRulesOptions> = {
|
|
1175
|
-
name: FormItemName;
|
|
1176
|
-
label?: Omit<FormLabelElementProps, 'name' | 'children'> & {
|
|
1177
|
-
Label?: ComponentType<FormLabelElementProps>;
|
|
1178
|
-
};
|
|
1179
|
-
input?: FormInputProps<FormElements>;
|
|
1180
|
-
rules?: FormRulesOptions;
|
|
1181
|
-
};
|
|
1182
|
-
declare function FormItem(props: FormItemProps): react_jsx_runtime0.JSX.Element;
|
|
1183
|
-
declare namespace FormItem {
|
|
1184
|
-
var displayName: string;
|
|
1185
|
-
}
|
|
1186
|
-
//#endregion
|
|
1187
|
-
//#region src/Form/Container.d.ts
|
|
1188
|
-
type FormProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
1189
|
-
items: FormItemProps<FormElements, InferFormRulesOptions<Rules>>[];
|
|
1190
|
-
onSubmit?: (values: Values) => Promise<void>;
|
|
1191
|
-
Elements?: Partial<FormElements>;
|
|
1192
|
-
lang?: Partial<FormLang>;
|
|
1193
|
-
defaultValues?: Values;
|
|
1194
|
-
rules?: typeof FormDefaultRules & Rules;
|
|
1195
|
-
};
|
|
1196
|
-
/**
|
|
1197
|
-
* Render a form with context, default elements, and validation state.
|
|
1198
|
-
*
|
|
1199
|
-
* `FormContainer` merges provided elements, language strings, and rules with
|
|
1200
|
-
* the package defaults, then exposes them through form context.
|
|
1201
|
-
*
|
|
1202
|
-
* @template Values - The type of form values, defaults to Record<string, any>.
|
|
1203
|
-
* @template FormElements - The type of form elements, defaults to FormElementTypes.
|
|
1204
|
-
* @template Rules - The type of form rules, defaults to FormDefaultRules.
|
|
1205
|
-
* @param props - Form items and optional overrides for defaults, language, rules, and submit behavior.
|
|
1206
|
-
* @returns React form container with shared form context.
|
|
1207
|
-
*
|
|
1208
|
-
* @example
|
|
1209
|
-
* ```tsx
|
|
1210
|
-
* import { Form } from '@faasjs/react'
|
|
1211
|
-
*
|
|
1212
|
-
* function MyForm() {
|
|
1213
|
-
* return (
|
|
1214
|
-
* <Form
|
|
1215
|
-
* items={[
|
|
1216
|
-
* { name: 'name' },
|
|
1217
|
-
* ]}
|
|
1218
|
-
* />
|
|
1219
|
-
* )
|
|
1220
|
-
* }
|
|
1221
|
-
* ```
|
|
1222
|
-
*/
|
|
1223
|
-
declare function FormContainer<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules>({
|
|
1224
|
-
defaultValues,
|
|
1225
|
-
Elements,
|
|
1226
|
-
rules,
|
|
1227
|
-
lang,
|
|
1228
|
-
items,
|
|
1229
|
-
...props
|
|
1230
|
-
}: FormProps<Values, FormElements, Rules>): react_jsx_runtime0.JSX.Element;
|
|
1231
|
-
declare namespace FormContainer {
|
|
1232
|
-
var displayName: string;
|
|
1233
|
-
}
|
|
1234
|
-
//#endregion
|
|
1235
|
-
//#region src/Form/context.d.ts
|
|
1236
|
-
type FormContextProps<Values extends Record<string, any> = Record<string, any>, FormElements extends FormElementTypes = FormElementTypes, Rules extends FormRules = typeof FormDefaultRules> = {
|
|
1237
|
-
items: FormItemProps<FormElements, InferFormRulesOptions<Rules>>[];
|
|
1238
|
-
onSubmit: (values: Values) => Promise<void>;
|
|
1239
|
-
Elements: FormElementTypes;
|
|
1240
|
-
lang: FormLang;
|
|
1241
|
-
rules: typeof FormDefaultRules & Rules;
|
|
1242
|
-
submitting: boolean;
|
|
1243
|
-
setSubmitting: Dispatch<SetStateAction<boolean>>;
|
|
1244
|
-
values: Values;
|
|
1245
|
-
setValues: Dispatch<SetStateAction<Values>>;
|
|
1246
|
-
errors: Record<string, Error>;
|
|
1247
|
-
setErrors: Dispatch<SetStateAction<Record<string, Error>>>;
|
|
1248
|
-
valuesRef: RefObject<Values>;
|
|
1249
|
-
};
|
|
1250
|
-
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(this: void, props: {
|
|
1251
|
-
value?: Partial<NewT>;
|
|
1252
|
-
children: react.ReactNode;
|
|
1253
|
-
memo?: true | any[];
|
|
1254
|
-
initializeStates?: Partial<NewT>;
|
|
1255
|
-
}) => react.ReactNode;
|
|
1256
|
-
declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(this: void) => Readonly<NewT>;
|
|
1257
|
-
//#endregion
|
|
1258
1044
|
//#region src/OptionalWrapper.d.ts
|
|
1259
1045
|
type OptionalWrapperProps<TWrapper extends ComponentType<{
|
|
1260
1046
|
children: ReactNode;
|
|
@@ -1522,4 +1308,4 @@ declare function usePrevious<T = any>(value: T): T | undefined;
|
|
|
1522
1308
|
*/
|
|
1523
1309
|
declare function useStateRef<T = any>(initialValue?: T): [T | null, Dispatch<SetStateAction<T | null>>, RefObject<T | null>];
|
|
1524
1310
|
//#endregion
|
|
1525
|
-
export { BaseUrl, ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, FaasBrowserClient, FaasBrowserClientAction, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions,
|
|
1311
|
+
export { BaseUrl, ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, FaasBrowserClient, FaasBrowserClientAction, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions, 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, usePrevious, useSplittingState, useStateRef, withFaasData };
|
package/dist/index.mjs
CHANGED
|
@@ -1076,43 +1076,33 @@ var ErrorBoundary = class extends Component {
|
|
|
1076
1076
|
}
|
|
1077
1077
|
};
|
|
1078
1078
|
//#endregion
|
|
1079
|
-
//#region src/
|
|
1079
|
+
//#region src/OptionalWrapper.tsx
|
|
1080
1080
|
/**
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
1083
|
-
* @template T - The type of the value.
|
|
1084
|
-
* @param initialValue - Initial state value. When omitted, state starts as `null`.
|
|
1085
|
-
* @returns Tuple containing the current state, the state setter, and a ref that always points at the latest state.
|
|
1081
|
+
* A wrapper component that conditionally wraps its children with a provided wrapper component.
|
|
1086
1082
|
*
|
|
1087
1083
|
* @example
|
|
1088
1084
|
* ```tsx
|
|
1089
|
-
* import {
|
|
1085
|
+
* import { OptionalWrapper } from '@faasjs/react'
|
|
1090
1086
|
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1087
|
+
* const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
1088
|
+
* <div className='wrapper'>{children}</div>
|
|
1089
|
+
* )
|
|
1093
1090
|
*
|
|
1094
|
-
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
*
|
|
1099
|
-
* </div>
|
|
1100
|
-
* )
|
|
1101
|
-
* }
|
|
1091
|
+
* const App = () => (
|
|
1092
|
+
* <OptionalWrapper condition={true} Wrapper={Wrapper}>
|
|
1093
|
+
* <span>Test</span>
|
|
1094
|
+
* </OptionalWrapper>
|
|
1095
|
+
* )
|
|
1102
1096
|
* ```
|
|
1103
1097
|
*/
|
|
1104
|
-
function
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
return [
|
|
1111
|
-
state,
|
|
1112
|
-
setState,
|
|
1113
|
-
ref
|
|
1114
|
-
];
|
|
1098
|
+
function OptionalWrapper({ condition, Wrapper, wrapperProps, children }) {
|
|
1099
|
+
if (condition) return /* @__PURE__ */ jsx(Wrapper, {
|
|
1100
|
+
...wrapperProps,
|
|
1101
|
+
children
|
|
1102
|
+
});
|
|
1103
|
+
return children;
|
|
1115
1104
|
}
|
|
1105
|
+
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1116
1106
|
//#endregion
|
|
1117
1107
|
//#region src/splittingState.tsx
|
|
1118
1108
|
/**
|
|
@@ -1225,278 +1215,6 @@ function createSplittingContext(defaultValue) {
|
|
|
1225
1215
|
};
|
|
1226
1216
|
}
|
|
1227
1217
|
//#endregion
|
|
1228
|
-
//#region src/Form/context.tsx
|
|
1229
|
-
const FormContext = createSplittingContext([
|
|
1230
|
-
"items",
|
|
1231
|
-
"onSubmit",
|
|
1232
|
-
"Elements",
|
|
1233
|
-
"lang",
|
|
1234
|
-
"rules",
|
|
1235
|
-
"submitting",
|
|
1236
|
-
"setSubmitting",
|
|
1237
|
-
"values",
|
|
1238
|
-
"setValues",
|
|
1239
|
-
"errors",
|
|
1240
|
-
"setErrors",
|
|
1241
|
-
"valuesRef"
|
|
1242
|
-
]);
|
|
1243
|
-
const FormContextProvider = FormContext.Provider;
|
|
1244
|
-
const useFormContext = FormContext.use;
|
|
1245
|
-
//#endregion
|
|
1246
|
-
//#region src/Form/Input.tsx
|
|
1247
|
-
function processValue(input, rules) {
|
|
1248
|
-
switch (rules?.type) {
|
|
1249
|
-
case "number": return Number(input);
|
|
1250
|
-
case "string": return String(input);
|
|
1251
|
-
default: return input;
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
function FormInput({ name, rules, ...rest }) {
|
|
1255
|
-
const { Elements, values, setValues } = useFormContext();
|
|
1256
|
-
const value = values?.[name];
|
|
1257
|
-
if (rest.Input) return /* @__PURE__ */ jsx(rest.Input, {
|
|
1258
|
-
name,
|
|
1259
|
-
value,
|
|
1260
|
-
onChange: (v) => setValues((prev) => ({
|
|
1261
|
-
...prev,
|
|
1262
|
-
[name]: processValue(v, rules)
|
|
1263
|
-
})),
|
|
1264
|
-
...rest.props
|
|
1265
|
-
});
|
|
1266
|
-
return /* @__PURE__ */ jsx(Elements.Input, {
|
|
1267
|
-
name,
|
|
1268
|
-
value,
|
|
1269
|
-
onChange: (v) => setValues((prev) => ({
|
|
1270
|
-
...prev,
|
|
1271
|
-
[name]: processValue(v, rules)
|
|
1272
|
-
})),
|
|
1273
|
-
...rest.props
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
FormInput.displayName = "FormInput";
|
|
1277
|
-
//#endregion
|
|
1278
|
-
//#region src/Form/Item.tsx
|
|
1279
|
-
function FormItem(props) {
|
|
1280
|
-
const { Elements, errors } = useFormContext();
|
|
1281
|
-
return /* @__PURE__ */ jsx(props.label?.Label ?? Elements.Label, {
|
|
1282
|
-
name: props.name,
|
|
1283
|
-
...props.label,
|
|
1284
|
-
error: errors[props.name],
|
|
1285
|
-
children: /* @__PURE__ */ jsx(FormInput, {
|
|
1286
|
-
name: props.name,
|
|
1287
|
-
...props.input,
|
|
1288
|
-
...props.rules ? { rules: props.rules } : {}
|
|
1289
|
-
})
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
|
-
FormItem.displayName = "FormItem";
|
|
1293
|
-
//#endregion
|
|
1294
|
-
//#region src/Form/Body.tsx
|
|
1295
|
-
function FormBody() {
|
|
1296
|
-
const { items } = useFormContext();
|
|
1297
|
-
return items.map((item) => /* @__PURE__ */ jsx(FormItem, { ...item }, item.name));
|
|
1298
|
-
}
|
|
1299
|
-
FormBody.displayName = "FormBody";
|
|
1300
|
-
//#endregion
|
|
1301
|
-
//#region src/Form/elements/Button.tsx
|
|
1302
|
-
const FormButtonElement = forwardRef(({ children, submit, submitting, ...props }, ref) => /* @__PURE__ */ jsx("button", {
|
|
1303
|
-
type: "button",
|
|
1304
|
-
disabled: submitting,
|
|
1305
|
-
onClick: submit,
|
|
1306
|
-
...props,
|
|
1307
|
-
ref,
|
|
1308
|
-
children
|
|
1309
|
-
}));
|
|
1310
|
-
FormButtonElement.displayName = "FormButtonElement";
|
|
1311
|
-
//#endregion
|
|
1312
|
-
//#region src/Form/elements/Input.tsx
|
|
1313
|
-
const FormInputElement = forwardRef(({ onChange, ...props }, ref) => /* @__PURE__ */ jsx("input", {
|
|
1314
|
-
...props,
|
|
1315
|
-
onChange: (e) => onChange(e.target.value),
|
|
1316
|
-
ref
|
|
1317
|
-
}));
|
|
1318
|
-
FormInputElement.displayName = "FormInputElement";
|
|
1319
|
-
//#endregion
|
|
1320
|
-
//#region src/Form/elements/Label.tsx
|
|
1321
|
-
const FormLabelElement = ({ name, title, description, error, children }) => {
|
|
1322
|
-
return /* @__PURE__ */ jsxs("label", { children: [
|
|
1323
|
-
title ?? name,
|
|
1324
|
-
children,
|
|
1325
|
-
description,
|
|
1326
|
-
error && /* @__PURE__ */ jsx("div", {
|
|
1327
|
-
style: { color: "red" },
|
|
1328
|
-
children: error.message
|
|
1329
|
-
})
|
|
1330
|
-
] });
|
|
1331
|
-
};
|
|
1332
|
-
FormLabelElement.displayName = "FormLabelElement";
|
|
1333
|
-
//#endregion
|
|
1334
|
-
//#region src/Form/elements/index.ts
|
|
1335
|
-
const FormDefaultElements = {
|
|
1336
|
-
Label: FormLabelElement,
|
|
1337
|
-
Input: FormInputElement,
|
|
1338
|
-
Button: FormButtonElement
|
|
1339
|
-
};
|
|
1340
|
-
//#endregion
|
|
1341
|
-
//#region src/Form/rules.ts
|
|
1342
|
-
/**
|
|
1343
|
-
* Default validation rules for a form.
|
|
1344
|
-
*/
|
|
1345
|
-
const FormDefaultRules = {
|
|
1346
|
-
required: async (value, _, lang) => {
|
|
1347
|
-
if (value === null || value === void 0 || value === "" || Number.isNaN(value)) throw Error(lang?.required);
|
|
1348
|
-
},
|
|
1349
|
-
type: async (value, options, lang) => {
|
|
1350
|
-
switch (options) {
|
|
1351
|
-
case "string":
|
|
1352
|
-
if (typeof value !== "string") throw Error(lang?.string);
|
|
1353
|
-
break;
|
|
1354
|
-
case "number":
|
|
1355
|
-
if (Number.isNaN(Number(value))) throw Error(lang?.number);
|
|
1356
|
-
break;
|
|
1357
|
-
}
|
|
1358
|
-
},
|
|
1359
|
-
custom: async (value, options) => {
|
|
1360
|
-
return options(value);
|
|
1361
|
-
}
|
|
1362
|
-
};
|
|
1363
|
-
async function validValues(rules, items, values, lang) {
|
|
1364
|
-
const errors = {};
|
|
1365
|
-
for (const item of items) {
|
|
1366
|
-
const value = values[item.name];
|
|
1367
|
-
const rulesOptions = item.rules;
|
|
1368
|
-
if (rulesOptions) for (const [name, options] of Object.entries(rulesOptions)) try {
|
|
1369
|
-
await rules[name](value, options, lang);
|
|
1370
|
-
} catch (error) {
|
|
1371
|
-
errors[item.name] = error;
|
|
1372
|
-
break;
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
return errors;
|
|
1376
|
-
}
|
|
1377
|
-
//#endregion
|
|
1378
|
-
//#region src/Form/Footer.tsx
|
|
1379
|
-
function FormFooter() {
|
|
1380
|
-
const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
|
|
1381
|
-
const Button = Elements.Button;
|
|
1382
|
-
return /* @__PURE__ */ jsx(Button, {
|
|
1383
|
-
submitting,
|
|
1384
|
-
submit: useCallback(async () => {
|
|
1385
|
-
setSubmitting(true);
|
|
1386
|
-
setErrors({});
|
|
1387
|
-
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1388
|
-
if (Object.keys(errors).length) {
|
|
1389
|
-
setErrors(errors);
|
|
1390
|
-
setSubmitting(false);
|
|
1391
|
-
return;
|
|
1392
|
-
}
|
|
1393
|
-
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1394
|
-
}, [
|
|
1395
|
-
setSubmitting,
|
|
1396
|
-
setErrors,
|
|
1397
|
-
rules,
|
|
1398
|
-
items,
|
|
1399
|
-
valuesRef,
|
|
1400
|
-
lang,
|
|
1401
|
-
onSubmit
|
|
1402
|
-
]),
|
|
1403
|
-
children: lang.submit
|
|
1404
|
-
});
|
|
1405
|
-
}
|
|
1406
|
-
FormFooter.displayName = "FormFooter";
|
|
1407
|
-
//#endregion
|
|
1408
|
-
//#region src/Form/lang.ts
|
|
1409
|
-
const FormDefaultLang = {
|
|
1410
|
-
submit: "Submit",
|
|
1411
|
-
required: "This field is required",
|
|
1412
|
-
string: "This field must be a string",
|
|
1413
|
-
number: "This field must be a number"
|
|
1414
|
-
};
|
|
1415
|
-
//#endregion
|
|
1416
|
-
//#region src/Form/Container.tsx
|
|
1417
|
-
function mergeValues(items, defaultValues = {}) {
|
|
1418
|
-
const values = {};
|
|
1419
|
-
for (const item of items) values[item.name] = defaultValues[item.name] ?? "";
|
|
1420
|
-
return values;
|
|
1421
|
-
}
|
|
1422
|
-
/**
|
|
1423
|
-
* Render a form with context, default elements, and validation state.
|
|
1424
|
-
*
|
|
1425
|
-
* `FormContainer` merges provided elements, language strings, and rules with
|
|
1426
|
-
* the package defaults, then exposes them through form context.
|
|
1427
|
-
*
|
|
1428
|
-
* @template Values - The type of form values, defaults to Record<string, any>.
|
|
1429
|
-
* @template FormElements - The type of form elements, defaults to FormElementTypes.
|
|
1430
|
-
* @template Rules - The type of form rules, defaults to FormDefaultRules.
|
|
1431
|
-
* @param props - Form items and optional overrides for defaults, language, rules, and submit behavior.
|
|
1432
|
-
* @returns React form container with shared form context.
|
|
1433
|
-
*
|
|
1434
|
-
* @example
|
|
1435
|
-
* ```tsx
|
|
1436
|
-
* import { Form } from '@faasjs/react'
|
|
1437
|
-
*
|
|
1438
|
-
* function MyForm() {
|
|
1439
|
-
* return (
|
|
1440
|
-
* <Form
|
|
1441
|
-
* items={[
|
|
1442
|
-
* { name: 'name' },
|
|
1443
|
-
* ]}
|
|
1444
|
-
* />
|
|
1445
|
-
* )
|
|
1446
|
-
* }
|
|
1447
|
-
* ```
|
|
1448
|
-
*/
|
|
1449
|
-
function FormContainer({ defaultValues, Elements, rules, lang, items, ...props }) {
|
|
1450
|
-
const [values, setValues, valuesRef] = useStateRef(mergeValues(items, defaultValues));
|
|
1451
|
-
return /* @__PURE__ */ jsxs(FormContextProvider, {
|
|
1452
|
-
initializeStates: {
|
|
1453
|
-
errors: {},
|
|
1454
|
-
submitting: false
|
|
1455
|
-
},
|
|
1456
|
-
value: {
|
|
1457
|
-
Elements: Object.assign(FormDefaultElements, Elements),
|
|
1458
|
-
lang: Object.assign(FormDefaultLang, lang),
|
|
1459
|
-
rules: Object.assign(FormDefaultRules, rules),
|
|
1460
|
-
items,
|
|
1461
|
-
values,
|
|
1462
|
-
setValues,
|
|
1463
|
-
valuesRef,
|
|
1464
|
-
...props
|
|
1465
|
-
},
|
|
1466
|
-
memo: true,
|
|
1467
|
-
children: [/* @__PURE__ */ jsx(FormBody, {}), /* @__PURE__ */ jsx(FormFooter, {})]
|
|
1468
|
-
});
|
|
1469
|
-
}
|
|
1470
|
-
FormContainer.displayName = "FormContainer";
|
|
1471
|
-
//#endregion
|
|
1472
|
-
//#region src/OptionalWrapper.tsx
|
|
1473
|
-
/**
|
|
1474
|
-
* A wrapper component that conditionally wraps its children with a provided wrapper component.
|
|
1475
|
-
*
|
|
1476
|
-
* @example
|
|
1477
|
-
* ```tsx
|
|
1478
|
-
* import { OptionalWrapper } from '@faasjs/react'
|
|
1479
|
-
*
|
|
1480
|
-
* const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
1481
|
-
* <div className='wrapper'>{children}</div>
|
|
1482
|
-
* )
|
|
1483
|
-
*
|
|
1484
|
-
* const App = () => (
|
|
1485
|
-
* <OptionalWrapper condition={true} Wrapper={Wrapper}>
|
|
1486
|
-
* <span>Test</span>
|
|
1487
|
-
* </OptionalWrapper>
|
|
1488
|
-
* )
|
|
1489
|
-
* ```
|
|
1490
|
-
*/
|
|
1491
|
-
function OptionalWrapper({ condition, Wrapper, wrapperProps, children }) {
|
|
1492
|
-
if (condition) return /* @__PURE__ */ jsx(Wrapper, {
|
|
1493
|
-
...wrapperProps,
|
|
1494
|
-
children
|
|
1495
|
-
});
|
|
1496
|
-
return children;
|
|
1497
|
-
}
|
|
1498
|
-
OptionalWrapper.displayName = "OptionalWrapper";
|
|
1499
|
-
//#endregion
|
|
1500
1218
|
//#region src/useFaasStream.tsx
|
|
1501
1219
|
/**
|
|
1502
1220
|
* Stream a FaasJS response into React state.
|
|
@@ -1665,4 +1383,42 @@ function usePrevious(value) {
|
|
|
1665
1383
|
return ref.current;
|
|
1666
1384
|
}
|
|
1667
1385
|
//#endregion
|
|
1668
|
-
|
|
1386
|
+
//#region src/useStateRef.ts
|
|
1387
|
+
/**
|
|
1388
|
+
* Custom hook that returns a stateful value and a ref to that value.
|
|
1389
|
+
*
|
|
1390
|
+
* @template T - The type of the value.
|
|
1391
|
+
* @param initialValue - Initial state value. When omitted, state starts as `null`.
|
|
1392
|
+
* @returns Tuple containing the current state, the state setter, and a ref that always points at the latest state.
|
|
1393
|
+
*
|
|
1394
|
+
* @example
|
|
1395
|
+
* ```tsx
|
|
1396
|
+
* import { useStateRef } from '@faasjs/react'
|
|
1397
|
+
*
|
|
1398
|
+
* function MyComponent() {
|
|
1399
|
+
* const [value, setValue, ref] = useStateRef(0)
|
|
1400
|
+
*
|
|
1401
|
+
* return (
|
|
1402
|
+
* <div>
|
|
1403
|
+
* <p>Value: {value}</p>
|
|
1404
|
+
* <button onClick={() => setValue(value + 1)}>Increment</button>
|
|
1405
|
+
* <button onClick={() => console.log(ref.current)}>Submit</button>
|
|
1406
|
+
* </div>
|
|
1407
|
+
* )
|
|
1408
|
+
* }
|
|
1409
|
+
* ```
|
|
1410
|
+
*/
|
|
1411
|
+
function useStateRef(initialValue) {
|
|
1412
|
+
const [state, setState] = useState(initialValue ?? null);
|
|
1413
|
+
const ref = useRef(state);
|
|
1414
|
+
useEffect(() => {
|
|
1415
|
+
ref.current = state;
|
|
1416
|
+
}, [state]);
|
|
1417
|
+
return [
|
|
1418
|
+
state,
|
|
1419
|
+
setState,
|
|
1420
|
+
ref
|
|
1421
|
+
];
|
|
1422
|
+
}
|
|
1423
|
+
//#endregion
|
|
1424
|
+
export { ErrorBoundary, FaasBrowserClient, FaasDataWrapper, FaasReactClient, OptionalWrapper, Response, ResponseError, createSplittingContext, equal, faas, generateId, getClient, setMock, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasStream, usePrevious, useSplittingState, useStateRef, 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.17",
|
|
4
4
|
"homepage": "https://faasjs.com/doc/react/",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/faasjs/faasjs/issues"
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
30
|
+
"@faasjs/types": ">=8.0.0-beta.17",
|
|
31
31
|
"@types/react": "^19.0.0",
|
|
32
32
|
"react": "^19.0.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
35
|
+
"@faasjs/types": ">=8.0.0-beta.17"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
38
|
"node": ">=24.0.0",
|