react-native-better-html 1.0.10 → 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"));
@@ -1187,6 +1311,10 @@ var InputFieldComponent = (0, import_react10.forwardRef)(
1187
1311
  defaultValue,
1188
1312
  value,
1189
1313
  editable = true,
1314
+ label,
1315
+ isError,
1316
+ infoMessage,
1317
+ errorMessage,
1190
1318
  autoFocus,
1191
1319
  autoCapitalize,
1192
1320
  autoComplete,
@@ -1201,6 +1329,8 @@ var InputFieldComponent = (0, import_react10.forwardRef)(
1201
1329
  fontWeight = 400,
1202
1330
  lineHeight = 20,
1203
1331
  textAlign,
1332
+ required,
1333
+ disabled,
1204
1334
  paddingHorizontal,
1205
1335
  paddingVertical,
1206
1336
  onFocus,
@@ -1257,84 +1387,124 @@ var InputFieldComponent = (0, import_react10.forwardRef)(
1257
1387
  []
1258
1388
  );
1259
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);
1260
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(View_default, { isRow: true, position: "relative", alignItems: "center", flex: 1, height: readyHeight, children: [
1261
- prefix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1262
- View_default,
1263
- {
1264
- isRow: true,
1265
- height: "100%",
1266
- backgroundColor: prefixSuffixBackgroundColor,
1267
- alignItems: "center",
1268
- borderWidth,
1269
- borderRightWidth: 0,
1270
- borderTopLeftRadius: theme2.styles.borderRadius,
1271
- borderBottomLeftRadius: theme2.styles.borderRadius,
1272
- borderColor: theme2.colors.border,
1273
- paddingHorizontal: readyPaddingHorizontal,
1274
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontWeight: 700, children: prefix })
1275
- }
1276
- ),
1277
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1278
- Animate_default.View,
1279
- {
1280
- flex: 1,
1281
- backgroundColor: theme2.colors.backgroundContent,
1282
- borderTopLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1283
- borderBottomLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1284
- borderTopRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1285
- borderBottomRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1286
- borderWidth,
1287
- initialBorderColor: theme2.colors.border,
1288
- animateBorderColor: isFocused ? theme2.colors.primary : theme2.colors.border,
1289
- overflow: "hidden",
1290
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1291
- 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,
1466
+ {
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
1478
+ }
1479
+ )
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,
1292
1495
  {
1293
- style: textInputStyle,
1294
- value: internalValue,
1295
- defaultValue,
1296
- autoCapitalize,
1297
- autoComplete,
1298
- autoCorrect,
1299
- autoFocus,
1300
- placeholder,
1301
- placeholderTextColor: theme2.colors.textSecondary + "80",
1302
- enterKeyHint: returnKeyLabel,
1303
- returnKeyType,
1304
- onSubmitEditing: onPressEnter,
1305
- readOnly: !editable,
1306
- textAlign,
1307
- keyboardAppearance,
1308
- keyboardType,
1309
- cursorColor: theme2.colors.primary,
1310
- selectionColor: theme2.colors.primary,
1311
- secureTextEntry,
1312
- onFocus: onFocusElement,
1313
- onBlur: onBlurElement,
1314
- onChangeText,
1315
- onPress,
1316
- ref: textInputRef
1496
+ fontSize: 14,
1497
+ color: theme2.colors.error,
1498
+ initialHeight: 0,
1499
+ initialOpacity: 0,
1500
+ animateHeight: 17,
1501
+ animateOpacity: 1,
1502
+ children: errorMessage
1317
1503
  }
1318
1504
  )
1319
- }
1320
- ),
1321
- suffix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1322
- View_default,
1323
- {
1324
- isRow: true,
1325
- height: "100%",
1326
- backgroundColor: prefixSuffixBackgroundColor,
1327
- alignItems: "center",
1328
- borderWidth,
1329
- borderLeftWidth: 0,
1330
- borderTopRightRadius: theme2.styles.borderRadius,
1331
- borderBottomRightRadius: theme2.styles.borderRadius,
1332
- borderColor: theme2.colors.border,
1333
- paddingHorizontal: readyPaddingHorizontal,
1334
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text_default, { fontWeight: 700, children: suffix })
1335
- }
1336
- )
1337
- ] });
1505
+ ]
1506
+ }
1507
+ );
1338
1508
  }
1339
1509
  );
1340
1510
  InputFieldComponent.email = (0, import_react10.forwardRef)(function Email(props, ref) {
@@ -1365,15 +1535,16 @@ InputFieldComponent.password = (0, import_react10.forwardRef)(function Password(
1365
1535
  }
1366
1536
  );
1367
1537
  });
1368
- InputFieldComponent.code = (0, import_react10.forwardRef)(function Password2(props, ref) {
1538
+ InputFieldComponent.code = (0, import_react10.forwardRef)(function Password2({ isSmall, ...props }, ref) {
1369
1539
  const theme2 = (0, import_react_better_core9.useTheme)();
1370
1540
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1371
1541
  InputFieldComponent,
1372
1542
  {
1373
- fontSize: 42,
1543
+ fontSize: isSmall ? 36 : 42,
1374
1544
  fontWeight: 900,
1375
- lineHeight: 50,
1376
- paddingVertical: theme2.styles.space * 2,
1545
+ lineHeight: isSmall ? 42 : 50,
1546
+ paddingVertical: isSmall ? theme2.styles.space : theme2.styles.space * 2,
1547
+ paddingHorizontal: isSmall ? theme2.styles.gap : void 0,
1377
1548
  textAlign: "center",
1378
1549
  ...props,
1379
1550
  ref
@@ -1391,12 +1562,13 @@ var import_react11 = require("react");
1391
1562
  var import_react_better_core10 = require("react-better-core");
1392
1563
  var import_react_native9 = require("react-native");
1393
1564
  var import_jsx_runtime10 = require("react/jsx-runtime");
1394
- function StatusBar({ darkStatusBar, hidden }) {
1565
+ function StatusBar({ darkStatusBar, hidden, barStyle, androidBarStyle, iOSBarStyle }) {
1395
1566
  const theme2 = (0, import_react_better_core10.useTheme)();
1396
1567
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1397
1568
  import_react_native9.StatusBar,
1398
1569
  {
1399
1570
  backgroundColor: darkStatusBar ? theme2.colors.backgroundSecondary : void 0,
1571
+ barStyle: barStyle ?? (import_react_native9.Platform.OS === "android" ? androidBarStyle : iOSBarStyle),
1400
1572
  hidden
1401
1573
  }
1402
1574
  );
@@ -1439,6 +1611,7 @@ var asyncStoragePlugin = (options) => ({
1439
1611
  formatPhoneNumber,
1440
1612
  generateAsyncStorage,
1441
1613
  generateRandomString,
1614
+ getFormErrorObject,
1442
1615
  getPluralWord,
1443
1616
  lightenColor,
1444
1617
  loaderControls,
@@ -1448,6 +1621,7 @@ var asyncStoragePlugin = (options) => ({
1448
1621
  useBooleanState,
1449
1622
  useDebounceState,
1450
1623
  useDevice,
1624
+ useForm,
1451
1625
  useKeyboard,
1452
1626
  useLoader,
1453
1627
  useLoaderControls,