react-native-better-html 1.0.11 → 1.0.12

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/dist/index.js CHANGED
@@ -52,6 +52,7 @@ __export(index_exports, {
52
52
  formatPhoneNumber: () => import_react_better_core11.formatPhoneNumber,
53
53
  generateAsyncStorage: () => generateAsyncStorage,
54
54
  generateRandomString: () => import_react_better_core11.generateRandomString,
55
+ getFormErrorObject: () => getFormErrorObject,
55
56
  getPluralWord: () => import_react_better_core11.getPluralWord,
56
57
  lightenColor: () => import_react_better_core11.lightenColor,
57
58
  loaderControls: () => import_react_better_core11.loaderControls,
@@ -61,6 +62,7 @@ __export(index_exports, {
61
62
  useBooleanState: () => import_react_better_core11.useBooleanState,
62
63
  useDebounceState: () => import_react_better_core11.useDebounceState,
63
64
  useDevice: () => useDevice,
65
+ useForm: () => useForm,
64
66
  useKeyboard: () => useKeyboard,
65
67
  useLoader: () => import_react_better_core11.useLoader,
66
68
  useLoaderControls: () => import_react_better_core11.useLoaderControls,
@@ -465,6 +467,128 @@ function useComponentPropsGrouper(props, prefix) {
465
467
  };
466
468
  }, [props, prefix]);
467
469
  }
470
+ function useForm(options) {
471
+ const { defaultValues, requiredFields, additional, onSubmit, validate } = options;
472
+ const inputFieldRefs = (0, import_react2.useRef)(
473
+ {}
474
+ );
475
+ const [values, setValues] = (0, import_react2.useState)(defaultValues);
476
+ const [errors, setErrors] = (0, import_react2.useState)({});
477
+ const [isSubmitting, setIsSubmitting] = (0, import_react_better_core2.useBooleanState)();
478
+ const numberOfInputFields = Object.keys(defaultValues).length;
479
+ const setFieldValue = (0, import_react2.useCallback)(
480
+ (field, value) => {
481
+ setValues((oldValue) => ({
482
+ ...oldValue,
483
+ [field]: value
484
+ }));
485
+ setErrors((oldValue) => ({
486
+ ...oldValue,
487
+ [field]: void 0
488
+ }));
489
+ },
490
+ []
491
+ );
492
+ const setFieldsValue = (0, import_react2.useCallback)((values2) => {
493
+ setValues((oldValue) => ({
494
+ ...oldValue,
495
+ ...values2
496
+ }));
497
+ setErrors((oldValue) => {
498
+ const newErrors = {};
499
+ for (const key in values2) newErrors[key] = void 0;
500
+ return newErrors;
501
+ });
502
+ }, []);
503
+ const focusField = (0, import_react2.useCallback)((field) => {
504
+ inputFieldRefs.current[field]?.focus();
505
+ }, []);
506
+ const validateForm = (0, import_react2.useCallback)(() => {
507
+ const validationErrors = validate?.(values) || {};
508
+ setErrors(validationErrors);
509
+ return validationErrors;
510
+ }, [validate, values]);
511
+ const onSubmitFunction = (0, import_react2.useCallback)(
512
+ async (event) => {
513
+ event?.preventDefault();
514
+ setIsSubmitting.setTrue();
515
+ try {
516
+ const validationErrors = validateForm();
517
+ if (Object.keys(validationErrors).length === 0) {
518
+ await onSubmit?.(values);
519
+ } else {
520
+ const firstErrorField = Object.keys(validationErrors)[0];
521
+ focusField(firstErrorField);
522
+ }
523
+ } finally {
524
+ setIsSubmitting.setFalse();
525
+ }
526
+ },
527
+ [values, validateForm, onSubmit, focusField]
528
+ );
529
+ const getInputFieldProps = (0, import_react2.useCallback)(
530
+ (field) => {
531
+ const thisInputFieldIndex = Object.keys(values).findIndex((key) => key === field);
532
+ const isLastInputField = thisInputFieldIndex === numberOfInputFields - 1;
533
+ return {
534
+ required: requiredFields?.includes(field),
535
+ value: values[field]?.toString() ?? "",
536
+ errorMessage: errors[field],
537
+ returnKeyLabel: isLastInputField ? additional?.lastInputFieldReturnKeyLabel ?? "done" : "next",
538
+ onPressEnter: () => {
539
+ if (isLastInputField) onSubmitFunction();
540
+ else inputFieldRefs.current[Object.keys(values)[thisInputFieldIndex + 1]]?.focus();
541
+ },
542
+ onChange: (value) => {
543
+ setFieldValue(field, value);
544
+ },
545
+ ref: (element) => {
546
+ if (!element) return;
547
+ inputFieldRefs.current[field] = element;
548
+ }
549
+ };
550
+ },
551
+ [values, setFieldValue, errors, requiredFields, additional, onSubmitFunction]
552
+ );
553
+ const reset = (0, import_react2.useCallback)(() => {
554
+ setValues(defaultValues);
555
+ setErrors({});
556
+ }, [defaultValues]);
557
+ const isDirty = (0, import_react2.useMemo)(
558
+ () => Object.keys(defaultValues).some((key) => defaultValues[key] !== values[key]),
559
+ [defaultValues, values]
560
+ );
561
+ const isValid = (0, import_react2.useMemo)(() => {
562
+ const validationErrors = validate?.(values) || {};
563
+ return Object.keys(validationErrors).length === 0;
564
+ }, [validate, values]);
565
+ const canSubmit = (0, import_react2.useMemo)(() => {
566
+ const requiredFieldsHaveValues = requiredFields?.every((field) => values[field] !== void 0 && values[field] !== "") ?? true;
567
+ return isValid && requiredFieldsHaveValues;
568
+ }, [isValid, requiredFields]);
569
+ return {
570
+ values,
571
+ errors,
572
+ isSubmitting,
573
+ setFieldValue,
574
+ setFieldsValue,
575
+ getInputFieldProps,
576
+ focusField,
577
+ inputFieldRefs: inputFieldRefs.current,
578
+ validate: validateForm,
579
+ onSubmit: onSubmitFunction,
580
+ reset,
581
+ requiredFields,
582
+ isDirty,
583
+ isValid,
584
+ canSubmit
585
+ };
586
+ }
587
+
588
+ // src/utils/functions.ts
589
+ var getFormErrorObject = (formValues) => {
590
+ return {};
591
+ };
468
592
 
469
593
  // src/utils/asyncStorage.ts
470
594
  var import_async_storage = __toESM(require("@react-native-async-storage/async-storage"));
@@ -1205,6 +1329,8 @@ var InputFieldComponent = (0, import_react10.forwardRef)(
1205
1329
  fontWeight = 400,
1206
1330
  lineHeight = 20,
1207
1331
  textAlign,
1332
+ required,
1333
+ disabled,
1208
1334
  paddingHorizontal,
1209
1335
  paddingVertical,
1210
1336
  onFocus,
@@ -1261,111 +1387,124 @@ var InputFieldComponent = (0, import_react10.forwardRef)(
1261
1387
  []
1262
1388
  );
1263
1389
  const prefixSuffixBackgroundColor = colorTheme === "light" ? (0, import_react_better_core9.darkenColor)(theme2.colors.backgroundContent, 0.03) : (0, import_react_better_core9.lightenColor)(theme2.colors.backgroundContent, 0.1);
1264
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(View_default, { flex: 1, gap: theme2.styles.gap / 3, children: [
1265
- label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontSize: 14, color: theme2.colors.textSecondary, children: label }),
1266
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(View_default, { isRow: true, position: "relative", alignItems: "center", flex: 1, height: readyHeight, children: [
1267
- prefix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1268
- View_default,
1269
- {
1270
- isRow: true,
1271
- height: "100%",
1272
- backgroundColor: prefixSuffixBackgroundColor,
1273
- alignItems: "center",
1274
- borderWidth,
1275
- borderRightWidth: 0,
1276
- borderTopLeftRadius: theme2.styles.borderRadius,
1277
- borderBottomLeftRadius: theme2.styles.borderRadius,
1278
- borderColor: theme2.colors.border,
1279
- paddingHorizontal: readyPaddingHorizontal,
1280
- children: typeof prefix === "string" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontWeight: 700, children: prefix }) : prefix
1281
- }
1282
- ),
1283
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1284
- Animate_default.View,
1285
- {
1286
- flex: 1,
1287
- backgroundColor: theme2.colors.backgroundContent,
1288
- borderTopLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1289
- borderBottomLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1290
- borderTopRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1291
- borderBottomRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1292
- borderWidth,
1293
- initialBorderColor: theme2.colors.border,
1294
- animateBorderColor: isFocused ? theme2.colors.primary : isError ? theme2.colors.error : theme2.colors.border,
1295
- overflow: "hidden",
1296
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1297
- import_react_native8.TextInput,
1390
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1391
+ Animate_default.View,
1392
+ {
1393
+ flex: 1,
1394
+ gap: theme2.styles.gap / 3,
1395
+ initialOpacity: 1,
1396
+ animateOpacity: disabled ? 0.6 : 1,
1397
+ children: [
1398
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(View_default, { isRow: true, width: "100%", alignItems: "center", gap: 2, children: [
1399
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontSize: 14, color: theme2.colors.textSecondary, children: label }),
1400
+ required && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { color: theme2.colors.error, children: "*" })
1401
+ ] }),
1402
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(View_default, { isRow: true, position: "relative", alignItems: "center", flex: 1, height: readyHeight, children: [
1403
+ prefix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1404
+ View_default,
1405
+ {
1406
+ isRow: true,
1407
+ height: "100%",
1408
+ backgroundColor: prefixSuffixBackgroundColor,
1409
+ alignItems: "center",
1410
+ borderWidth,
1411
+ borderRightWidth: 0,
1412
+ borderTopLeftRadius: theme2.styles.borderRadius,
1413
+ borderBottomLeftRadius: theme2.styles.borderRadius,
1414
+ borderColor: theme2.colors.border,
1415
+ paddingHorizontal: readyPaddingHorizontal,
1416
+ children: typeof prefix === "string" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontWeight: 700, children: prefix }) : prefix
1417
+ }
1418
+ ),
1419
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1420
+ Animate_default.View,
1421
+ {
1422
+ flex: 1,
1423
+ backgroundColor: theme2.colors.backgroundContent,
1424
+ borderTopLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1425
+ borderBottomLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1426
+ borderTopRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1427
+ borderBottomRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1428
+ borderWidth,
1429
+ initialBorderColor: theme2.colors.border,
1430
+ animateBorderColor: isFocused ? theme2.colors.primary : isError ? theme2.colors.error : theme2.colors.border,
1431
+ overflow: "hidden",
1432
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1433
+ import_react_native8.TextInput,
1434
+ {
1435
+ style: textInputStyle,
1436
+ value: internalValue,
1437
+ defaultValue,
1438
+ autoCapitalize,
1439
+ autoComplete,
1440
+ autoCorrect,
1441
+ autoFocus,
1442
+ placeholder,
1443
+ placeholderTextColor: theme2.colors.textSecondary + "80",
1444
+ enterKeyHint: returnKeyLabel,
1445
+ returnKeyType,
1446
+ onSubmitEditing: onPressEnter,
1447
+ readOnly: !editable || disabled,
1448
+ textAlign,
1449
+ editable: !disabled,
1450
+ keyboardAppearance,
1451
+ keyboardType,
1452
+ cursorColor: theme2.colors.primary,
1453
+ selectionColor: theme2.colors.primary,
1454
+ secureTextEntry,
1455
+ onFocus: onFocusElement,
1456
+ onBlur: onBlurElement,
1457
+ onChangeText,
1458
+ onPress,
1459
+ ref: textInputRef
1460
+ }
1461
+ )
1462
+ }
1463
+ ),
1464
+ suffix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1465
+ View_default,
1298
1466
  {
1299
- style: textInputStyle,
1300
- value: internalValue,
1301
- defaultValue,
1302
- autoCapitalize,
1303
- autoComplete,
1304
- autoCorrect,
1305
- autoFocus,
1306
- placeholder,
1307
- placeholderTextColor: theme2.colors.textSecondary + "80",
1308
- enterKeyHint: returnKeyLabel,
1309
- returnKeyType,
1310
- onSubmitEditing: onPressEnter,
1311
- readOnly: !editable,
1312
- textAlign,
1313
- keyboardAppearance,
1314
- keyboardType,
1315
- cursorColor: theme2.colors.primary,
1316
- selectionColor: theme2.colors.primary,
1317
- secureTextEntry,
1318
- onFocus: onFocusElement,
1319
- onBlur: onBlurElement,
1320
- onChangeText,
1321
- onPress,
1322
- ref: textInputRef
1467
+ isRow: true,
1468
+ height: "100%",
1469
+ backgroundColor: prefixSuffixBackgroundColor,
1470
+ alignItems: "center",
1471
+ borderWidth,
1472
+ borderLeftWidth: 0,
1473
+ borderTopRightRadius: theme2.styles.borderRadius,
1474
+ borderBottomRightRadius: theme2.styles.borderRadius,
1475
+ borderColor: theme2.colors.border,
1476
+ paddingHorizontal: readyPaddingHorizontal,
1477
+ children: typeof suffix === "string" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontWeight: 700, children: suffix }) : suffix
1323
1478
  }
1324
1479
  )
1325
- }
1326
- ),
1327
- suffix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1328
- View_default,
1329
- {
1330
- isRow: true,
1331
- height: "100%",
1332
- backgroundColor: prefixSuffixBackgroundColor,
1333
- alignItems: "center",
1334
- borderWidth,
1335
- borderLeftWidth: 0,
1336
- borderTopRightRadius: theme2.styles.borderRadius,
1337
- borderBottomRightRadius: theme2.styles.borderRadius,
1338
- borderColor: theme2.colors.border,
1339
- paddingHorizontal: readyPaddingHorizontal,
1340
- children: typeof suffix === "string" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontWeight: 700, children: suffix }) : suffix
1341
- }
1342
- )
1343
- ] }),
1344
- infoMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1345
- Animate_default.Text,
1346
- {
1347
- fontSize: 14,
1348
- color: theme2.colors.textSecondary,
1349
- initialHeight: 0,
1350
- initialOpacity: 0,
1351
- animateHeight: 17,
1352
- animateOpacity: 1,
1353
- children: infoMessage
1354
- }
1355
- ),
1356
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1357
- Animate_default.Text,
1358
- {
1359
- fontSize: 14,
1360
- color: theme2.colors.error,
1361
- initialHeight: 0,
1362
- initialOpacity: 0,
1363
- animateHeight: 17,
1364
- animateOpacity: 1,
1365
- children: errorMessage
1366
- }
1367
- )
1368
- ] });
1480
+ ] }),
1481
+ infoMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1482
+ Animate_default.Text,
1483
+ {
1484
+ fontSize: 14,
1485
+ color: theme2.colors.textSecondary,
1486
+ initialHeight: 0,
1487
+ initialOpacity: 0,
1488
+ animateHeight: 17,
1489
+ animateOpacity: 1,
1490
+ children: infoMessage
1491
+ }
1492
+ ),
1493
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1494
+ Animate_default.Text,
1495
+ {
1496
+ fontSize: 14,
1497
+ color: theme2.colors.error,
1498
+ initialHeight: 0,
1499
+ initialOpacity: 0,
1500
+ animateHeight: 17,
1501
+ animateOpacity: 1,
1502
+ children: errorMessage
1503
+ }
1504
+ )
1505
+ ]
1506
+ }
1507
+ );
1369
1508
  }
1370
1509
  );
1371
1510
  InputFieldComponent.email = (0, import_react10.forwardRef)(function Email(props, ref) {
@@ -1472,6 +1611,7 @@ var asyncStoragePlugin = (options) => ({
1472
1611
  formatPhoneNumber,
1473
1612
  generateAsyncStorage,
1474
1613
  generateRandomString,
1614
+ getFormErrorObject,
1475
1615
  getPluralWord,
1476
1616
  lightenColor,
1477
1617
  loaderControls,
@@ -1481,6 +1621,7 @@ var asyncStoragePlugin = (options) => ({
1481
1621
  useBooleanState,
1482
1622
  useDebounceState,
1483
1623
  useDevice,
1624
+ useForm,
1484
1625
  useKeyboard,
1485
1626
  useLoader,
1486
1627
  useLoaderControls,