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.mjs CHANGED
@@ -145,7 +145,7 @@ var pressStrength = () => {
145
145
  };
146
146
 
147
147
  // src/utils/hooks.ts
148
- import { useEffect as useEffect2, useMemo as useMemo2, useState } from "react";
148
+ import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef, useState } from "react";
149
149
  import { Dimensions, Keyboard } from "react-native";
150
150
  import { useSafeAreaInsets } from "react-native-safe-area-context";
151
151
  import { useBooleanState as useBooleanState2, useTheme } from "react-better-core";
@@ -420,6 +420,128 @@ function useComponentPropsGrouper(props, prefix) {
420
420
  };
421
421
  }, [props, prefix]);
422
422
  }
423
+ function useForm(options) {
424
+ const { defaultValues, requiredFields, additional, onSubmit, validate } = options;
425
+ const inputFieldRefs = useRef(
426
+ {}
427
+ );
428
+ const [values, setValues] = useState(defaultValues);
429
+ const [errors, setErrors] = useState({});
430
+ const [isSubmitting, setIsSubmitting] = useBooleanState2();
431
+ const numberOfInputFields = Object.keys(defaultValues).length;
432
+ const setFieldValue = useCallback(
433
+ (field, value) => {
434
+ setValues((oldValue) => ({
435
+ ...oldValue,
436
+ [field]: value
437
+ }));
438
+ setErrors((oldValue) => ({
439
+ ...oldValue,
440
+ [field]: void 0
441
+ }));
442
+ },
443
+ []
444
+ );
445
+ const setFieldsValue = useCallback((values2) => {
446
+ setValues((oldValue) => ({
447
+ ...oldValue,
448
+ ...values2
449
+ }));
450
+ setErrors((oldValue) => {
451
+ const newErrors = {};
452
+ for (const key in values2) newErrors[key] = void 0;
453
+ return newErrors;
454
+ });
455
+ }, []);
456
+ const focusField = useCallback((field) => {
457
+ inputFieldRefs.current[field]?.focus();
458
+ }, []);
459
+ const validateForm = useCallback(() => {
460
+ const validationErrors = validate?.(values) || {};
461
+ setErrors(validationErrors);
462
+ return validationErrors;
463
+ }, [validate, values]);
464
+ const onSubmitFunction = useCallback(
465
+ async (event) => {
466
+ event?.preventDefault();
467
+ setIsSubmitting.setTrue();
468
+ try {
469
+ const validationErrors = validateForm();
470
+ if (Object.keys(validationErrors).length === 0) {
471
+ await onSubmit?.(values);
472
+ } else {
473
+ const firstErrorField = Object.keys(validationErrors)[0];
474
+ focusField(firstErrorField);
475
+ }
476
+ } finally {
477
+ setIsSubmitting.setFalse();
478
+ }
479
+ },
480
+ [values, validateForm, onSubmit, focusField]
481
+ );
482
+ const getInputFieldProps = useCallback(
483
+ (field) => {
484
+ const thisInputFieldIndex = Object.keys(values).findIndex((key) => key === field);
485
+ const isLastInputField = thisInputFieldIndex === numberOfInputFields - 1;
486
+ return {
487
+ required: requiredFields?.includes(field),
488
+ value: values[field]?.toString() ?? "",
489
+ errorMessage: errors[field],
490
+ returnKeyLabel: isLastInputField ? additional?.lastInputFieldReturnKeyLabel ?? "done" : "next",
491
+ onPressEnter: () => {
492
+ if (isLastInputField) onSubmitFunction();
493
+ else inputFieldRefs.current[Object.keys(values)[thisInputFieldIndex + 1]]?.focus();
494
+ },
495
+ onChange: (value) => {
496
+ setFieldValue(field, value);
497
+ },
498
+ ref: (element) => {
499
+ if (!element) return;
500
+ inputFieldRefs.current[field] = element;
501
+ }
502
+ };
503
+ },
504
+ [values, setFieldValue, errors, requiredFields, additional, onSubmitFunction]
505
+ );
506
+ const reset = useCallback(() => {
507
+ setValues(defaultValues);
508
+ setErrors({});
509
+ }, [defaultValues]);
510
+ const isDirty = useMemo2(
511
+ () => Object.keys(defaultValues).some((key) => defaultValues[key] !== values[key]),
512
+ [defaultValues, values]
513
+ );
514
+ const isValid = useMemo2(() => {
515
+ const validationErrors = validate?.(values) || {};
516
+ return Object.keys(validationErrors).length === 0;
517
+ }, [validate, values]);
518
+ const canSubmit = useMemo2(() => {
519
+ const requiredFieldsHaveValues = requiredFields?.every((field) => values[field] !== void 0 && values[field] !== "") ?? true;
520
+ return isValid && requiredFieldsHaveValues;
521
+ }, [isValid, requiredFields]);
522
+ return {
523
+ values,
524
+ errors,
525
+ isSubmitting,
526
+ setFieldValue,
527
+ setFieldsValue,
528
+ getInputFieldProps,
529
+ focusField,
530
+ inputFieldRefs: inputFieldRefs.current,
531
+ validate: validateForm,
532
+ onSubmit: onSubmitFunction,
533
+ reset,
534
+ requiredFields,
535
+ isDirty,
536
+ isValid,
537
+ canSubmit
538
+ };
539
+ }
540
+
541
+ // src/utils/functions.ts
542
+ var getFormErrorObject = (formValues) => {
543
+ return {};
544
+ };
423
545
 
424
546
  // src/utils/asyncStorage.ts
425
547
  import NativeAsyncStorage from "@react-native-async-storage/async-storage";
@@ -975,7 +1097,7 @@ Button2.text = ButtonComponent.text;
975
1097
  var Button_default = Button2;
976
1098
 
977
1099
  // src/components/ScreenHolder.tsx
978
- import { memo as memo7, useCallback, useMemo as useMemo6 } from "react";
1100
+ import { memo as memo7, useCallback as useCallback2, useMemo as useMemo6 } from "react";
979
1101
  import { KeyboardAvoidingView, Platform as Platform3, RefreshControl, ScrollView } from "react-native";
980
1102
  import { useBooleanState as useBooleanState3, useTheme as useTheme6 } from "react-better-core";
981
1103
  import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -1005,7 +1127,7 @@ var ScreenHolderComponent = ({
1005
1127
  }),
1006
1128
  []
1007
1129
  );
1008
- const onRefreshElement = useCallback(() => {
1130
+ const onRefreshElement = useCallback2(() => {
1009
1131
  setIsRefreshing.setTrue();
1010
1132
  onRefresh?.();
1011
1133
  setTimeout(() => {
@@ -1141,15 +1263,15 @@ var Image_default = Image2;
1141
1263
  import {
1142
1264
  forwardRef,
1143
1265
  memo as memo9,
1144
- useCallback as useCallback2,
1266
+ useCallback as useCallback3,
1145
1267
  useEffect as useEffect4,
1146
1268
  useImperativeHandle,
1147
1269
  useMemo as useMemo8,
1148
- useRef,
1270
+ useRef as useRef2,
1149
1271
  useState as useState2
1150
1272
  } from "react";
1151
1273
  import {
1152
- TextInput
1274
+ TextInput as TextInput2
1153
1275
  } from "react-native";
1154
1276
  import {
1155
1277
  darkenColor,
@@ -1167,6 +1289,10 @@ var InputFieldComponent = forwardRef(
1167
1289
  defaultValue,
1168
1290
  value,
1169
1291
  editable = true,
1292
+ label,
1293
+ isError,
1294
+ infoMessage,
1295
+ errorMessage,
1170
1296
  autoFocus,
1171
1297
  autoCapitalize,
1172
1298
  autoComplete,
@@ -1181,6 +1307,8 @@ var InputFieldComponent = forwardRef(
1181
1307
  fontWeight = 400,
1182
1308
  lineHeight = 20,
1183
1309
  textAlign,
1310
+ required,
1311
+ disabled,
1184
1312
  paddingHorizontal,
1185
1313
  paddingVertical,
1186
1314
  onFocus,
@@ -1191,22 +1319,22 @@ var InputFieldComponent = forwardRef(
1191
1319
  }, ref) => {
1192
1320
  const theme2 = useTheme8();
1193
1321
  const { colorTheme } = useBetterCoreContext3();
1194
- const textInputRef = useRef(null);
1322
+ const textInputRef = useRef2(null);
1195
1323
  const [internalValue, setInternalValue] = useState2(value?.toString() || defaultValue || "");
1196
1324
  const [isFocused, setIsFocused] = useBooleanState4();
1197
1325
  const borderWidth = 1;
1198
1326
  const readyPaddingHorizontal = paddingHorizontal ?? theme2.styles.space;
1199
1327
  const readyPaddingVertical = paddingVertical ? parseFloat(paddingVertical.toString()) : (theme2.styles.space + theme2.styles.gap) / 2;
1200
1328
  const readyHeight = height ?? borderWidth + readyPaddingVertical + lineHeight + readyPaddingVertical + borderWidth;
1201
- const onFocusElement = useCallback2((event) => {
1329
+ const onFocusElement = useCallback3((event) => {
1202
1330
  setIsFocused.setTrue();
1203
1331
  onFocus?.(event);
1204
1332
  }, []);
1205
- const onBlurElement = useCallback2((event) => {
1333
+ const onBlurElement = useCallback3((event) => {
1206
1334
  setIsFocused.setFalse();
1207
1335
  onBlur?.(event);
1208
1336
  }, []);
1209
- const onChangeText = useCallback2(
1337
+ const onChangeText = useCallback3(
1210
1338
  (text) => {
1211
1339
  setInternalValue(text);
1212
1340
  onChange?.(text);
@@ -1237,84 +1365,124 @@ var InputFieldComponent = forwardRef(
1237
1365
  []
1238
1366
  );
1239
1367
  const prefixSuffixBackgroundColor = colorTheme === "light" ? darkenColor(theme2.colors.backgroundContent, 0.03) : lightenColor(theme2.colors.backgroundContent, 0.1);
1240
- return /* @__PURE__ */ jsxs4(View_default, { isRow: true, position: "relative", alignItems: "center", flex: 1, height: readyHeight, children: [
1241
- prefix && /* @__PURE__ */ jsx9(
1242
- View_default,
1243
- {
1244
- isRow: true,
1245
- height: "100%",
1246
- backgroundColor: prefixSuffixBackgroundColor,
1247
- alignItems: "center",
1248
- borderWidth,
1249
- borderRightWidth: 0,
1250
- borderTopLeftRadius: theme2.styles.borderRadius,
1251
- borderBottomLeftRadius: theme2.styles.borderRadius,
1252
- borderColor: theme2.colors.border,
1253
- paddingHorizontal: readyPaddingHorizontal,
1254
- children: /* @__PURE__ */ jsx9(Text_default, { fontWeight: 700, children: prefix })
1255
- }
1256
- ),
1257
- /* @__PURE__ */ jsx9(
1258
- Animate_default.View,
1259
- {
1260
- flex: 1,
1261
- backgroundColor: theme2.colors.backgroundContent,
1262
- borderTopLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1263
- borderBottomLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1264
- borderTopRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1265
- borderBottomRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1266
- borderWidth,
1267
- initialBorderColor: theme2.colors.border,
1268
- animateBorderColor: isFocused ? theme2.colors.primary : theme2.colors.border,
1269
- overflow: "hidden",
1270
- children: /* @__PURE__ */ jsx9(
1271
- TextInput,
1368
+ return /* @__PURE__ */ jsxs4(
1369
+ Animate_default.View,
1370
+ {
1371
+ flex: 1,
1372
+ gap: theme2.styles.gap / 3,
1373
+ initialOpacity: 1,
1374
+ animateOpacity: disabled ? 0.6 : 1,
1375
+ children: [
1376
+ label && /* @__PURE__ */ jsxs4(View_default, { isRow: true, width: "100%", alignItems: "center", gap: 2, children: [
1377
+ /* @__PURE__ */ jsx9(Text_default, { fontSize: 14, color: theme2.colors.textSecondary, children: label }),
1378
+ required && /* @__PURE__ */ jsx9(Text_default, { color: theme2.colors.error, children: "*" })
1379
+ ] }),
1380
+ /* @__PURE__ */ jsxs4(View_default, { isRow: true, position: "relative", alignItems: "center", flex: 1, height: readyHeight, children: [
1381
+ prefix && /* @__PURE__ */ jsx9(
1382
+ View_default,
1383
+ {
1384
+ isRow: true,
1385
+ height: "100%",
1386
+ backgroundColor: prefixSuffixBackgroundColor,
1387
+ alignItems: "center",
1388
+ borderWidth,
1389
+ borderRightWidth: 0,
1390
+ borderTopLeftRadius: theme2.styles.borderRadius,
1391
+ borderBottomLeftRadius: theme2.styles.borderRadius,
1392
+ borderColor: theme2.colors.border,
1393
+ paddingHorizontal: readyPaddingHorizontal,
1394
+ children: typeof prefix === "string" ? /* @__PURE__ */ jsx9(Text_default, { fontWeight: 700, children: prefix }) : prefix
1395
+ }
1396
+ ),
1397
+ /* @__PURE__ */ jsx9(
1398
+ Animate_default.View,
1399
+ {
1400
+ flex: 1,
1401
+ backgroundColor: theme2.colors.backgroundContent,
1402
+ borderTopLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1403
+ borderBottomLeftRadius: prefix ? 0 : theme2.styles.borderRadius,
1404
+ borderTopRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1405
+ borderBottomRightRadius: suffix ? 0 : theme2.styles.borderRadius,
1406
+ borderWidth,
1407
+ initialBorderColor: theme2.colors.border,
1408
+ animateBorderColor: isFocused ? theme2.colors.primary : isError ? theme2.colors.error : theme2.colors.border,
1409
+ overflow: "hidden",
1410
+ children: /* @__PURE__ */ jsx9(
1411
+ TextInput2,
1412
+ {
1413
+ style: textInputStyle,
1414
+ value: internalValue,
1415
+ defaultValue,
1416
+ autoCapitalize,
1417
+ autoComplete,
1418
+ autoCorrect,
1419
+ autoFocus,
1420
+ placeholder,
1421
+ placeholderTextColor: theme2.colors.textSecondary + "80",
1422
+ enterKeyHint: returnKeyLabel,
1423
+ returnKeyType,
1424
+ onSubmitEditing: onPressEnter,
1425
+ readOnly: !editable || disabled,
1426
+ textAlign,
1427
+ editable: !disabled,
1428
+ keyboardAppearance,
1429
+ keyboardType,
1430
+ cursorColor: theme2.colors.primary,
1431
+ selectionColor: theme2.colors.primary,
1432
+ secureTextEntry,
1433
+ onFocus: onFocusElement,
1434
+ onBlur: onBlurElement,
1435
+ onChangeText,
1436
+ onPress,
1437
+ ref: textInputRef
1438
+ }
1439
+ )
1440
+ }
1441
+ ),
1442
+ suffix && /* @__PURE__ */ jsx9(
1443
+ View_default,
1444
+ {
1445
+ isRow: true,
1446
+ height: "100%",
1447
+ backgroundColor: prefixSuffixBackgroundColor,
1448
+ alignItems: "center",
1449
+ borderWidth,
1450
+ borderLeftWidth: 0,
1451
+ borderTopRightRadius: theme2.styles.borderRadius,
1452
+ borderBottomRightRadius: theme2.styles.borderRadius,
1453
+ borderColor: theme2.colors.border,
1454
+ paddingHorizontal: readyPaddingHorizontal,
1455
+ children: typeof suffix === "string" ? /* @__PURE__ */ jsx9(Text_default, { fontWeight: 700, children: suffix }) : suffix
1456
+ }
1457
+ )
1458
+ ] }),
1459
+ infoMessage && /* @__PURE__ */ jsx9(
1460
+ Animate_default.Text,
1461
+ {
1462
+ fontSize: 14,
1463
+ color: theme2.colors.textSecondary,
1464
+ initialHeight: 0,
1465
+ initialOpacity: 0,
1466
+ animateHeight: 17,
1467
+ animateOpacity: 1,
1468
+ children: infoMessage
1469
+ }
1470
+ ),
1471
+ errorMessage && /* @__PURE__ */ jsx9(
1472
+ Animate_default.Text,
1272
1473
  {
1273
- style: textInputStyle,
1274
- value: internalValue,
1275
- defaultValue,
1276
- autoCapitalize,
1277
- autoComplete,
1278
- autoCorrect,
1279
- autoFocus,
1280
- placeholder,
1281
- placeholderTextColor: theme2.colors.textSecondary + "80",
1282
- enterKeyHint: returnKeyLabel,
1283
- returnKeyType,
1284
- onSubmitEditing: onPressEnter,
1285
- readOnly: !editable,
1286
- textAlign,
1287
- keyboardAppearance,
1288
- keyboardType,
1289
- cursorColor: theme2.colors.primary,
1290
- selectionColor: theme2.colors.primary,
1291
- secureTextEntry,
1292
- onFocus: onFocusElement,
1293
- onBlur: onBlurElement,
1294
- onChangeText,
1295
- onPress,
1296
- ref: textInputRef
1474
+ fontSize: 14,
1475
+ color: theme2.colors.error,
1476
+ initialHeight: 0,
1477
+ initialOpacity: 0,
1478
+ animateHeight: 17,
1479
+ animateOpacity: 1,
1480
+ children: errorMessage
1297
1481
  }
1298
1482
  )
1299
- }
1300
- ),
1301
- suffix && /* @__PURE__ */ jsx9(
1302
- View_default,
1303
- {
1304
- isRow: true,
1305
- height: "100%",
1306
- backgroundColor: prefixSuffixBackgroundColor,
1307
- alignItems: "center",
1308
- borderWidth,
1309
- borderLeftWidth: 0,
1310
- borderTopRightRadius: theme2.styles.borderRadius,
1311
- borderBottomRightRadius: theme2.styles.borderRadius,
1312
- borderColor: theme2.colors.border,
1313
- paddingHorizontal: readyPaddingHorizontal,
1314
- children: /* @__PURE__ */ jsx9(Text_default, { fontWeight: 700, children: suffix })
1315
- }
1316
- )
1317
- ] });
1483
+ ]
1484
+ }
1485
+ );
1318
1486
  }
1319
1487
  );
1320
1488
  InputFieldComponent.email = forwardRef(function Email(props, ref) {
@@ -1345,15 +1513,16 @@ InputFieldComponent.password = forwardRef(function Password(props, ref) {
1345
1513
  }
1346
1514
  );
1347
1515
  });
1348
- InputFieldComponent.code = forwardRef(function Password2(props, ref) {
1516
+ InputFieldComponent.code = forwardRef(function Password2({ isSmall, ...props }, ref) {
1349
1517
  const theme2 = useTheme8();
1350
1518
  return /* @__PURE__ */ jsx9(
1351
1519
  InputFieldComponent,
1352
1520
  {
1353
- fontSize: 42,
1521
+ fontSize: isSmall ? 36 : 42,
1354
1522
  fontWeight: 900,
1355
- lineHeight: 50,
1356
- paddingVertical: theme2.styles.space * 2,
1523
+ lineHeight: isSmall ? 42 : 50,
1524
+ paddingVertical: isSmall ? theme2.styles.space : theme2.styles.space * 2,
1525
+ paddingHorizontal: isSmall ? theme2.styles.gap : void 0,
1357
1526
  textAlign: "center",
1358
1527
  ...props,
1359
1528
  ref
@@ -1369,14 +1538,15 @@ var InputField_default = InputField;
1369
1538
  // src/components/StatusBar.tsx
1370
1539
  import { memo as memo10 } from "react";
1371
1540
  import { useTheme as useTheme9 } from "react-better-core";
1372
- import { StatusBar as NativeStatusBar } from "react-native";
1541
+ import { StatusBar as NativeStatusBar, Platform as Platform4 } from "react-native";
1373
1542
  import { jsx as jsx10 } from "react/jsx-runtime";
1374
- function StatusBar({ darkStatusBar, hidden }) {
1543
+ function StatusBar({ darkStatusBar, hidden, barStyle, androidBarStyle, iOSBarStyle }) {
1375
1544
  const theme2 = useTheme9();
1376
1545
  return /* @__PURE__ */ jsx10(
1377
1546
  NativeStatusBar,
1378
1547
  {
1379
1548
  backgroundColor: darkStatusBar ? theme2.colors.backgroundSecondary : void 0,
1549
+ barStyle: barStyle ?? (Platform4.OS === "android" ? androidBarStyle : iOSBarStyle),
1380
1550
  hidden
1381
1551
  }
1382
1552
  );
@@ -1418,6 +1588,7 @@ export {
1418
1588
  formatPhoneNumber,
1419
1589
  generateAsyncStorage,
1420
1590
  generateRandomString,
1591
+ getFormErrorObject,
1421
1592
  getPluralWord,
1422
1593
  lightenColor2 as lightenColor,
1423
1594
  loaderControls,
@@ -1427,6 +1598,7 @@ export {
1427
1598
  useBooleanState5 as useBooleanState,
1428
1599
  useDebounceState,
1429
1600
  useDevice,
1601
+ useForm,
1430
1602
  useKeyboard,
1431
1603
  useLoader2 as useLoader,
1432
1604
  useLoaderControls,