@hoddy-ui/core 1.1.0 → 1.1.2

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.
@@ -275,235 +275,245 @@ const TextField: React.FC<TextFieldProps> = ({
275
275
  );
276
276
  };
277
277
 
278
- export const TextField2: React.FC<TextFieldProps> = ({
279
- label,
280
- keyboardType,
281
- color = "primary",
282
- value,
283
- type,
284
- helperText,
285
- onChangeText,
286
- onSubmitEditing = () => {},
287
- onFocus = () => {},
288
- onBlur = () => {},
289
- error,
290
- start,
291
- rounded,
292
- disabled = false,
293
- style = {},
294
- inputStyles = {},
295
- gutterBottom = 8,
296
- placeholder,
297
- end,
298
- options,
299
- ...props
300
- }) => {
301
- const colors = useColors();
302
- const [focused, _setFocused] = useState(false);
303
- const [showPassword, setShowPassword] = useState(false);
278
+ export const TextField2 = React.forwardRef<TextInput, TextFieldProps>(
279
+ (
280
+ {
281
+ label,
282
+ keyboardType,
283
+ color = "primary",
284
+ value,
285
+ type,
286
+ helperText,
287
+ onChangeText,
288
+ onSubmitEditing = () => {},
289
+ onFocus = () => {},
290
+ onBlur = () => {},
291
+ error,
292
+ start,
293
+ rounded,
294
+ disabled = false,
295
+ style = {},
296
+ inputStyles = {},
297
+ gutterBottom = 8,
298
+ placeholder,
299
+ end,
300
+ options,
301
+ multiline,
302
+ ...props
303
+ },
304
+ ref
305
+ ) => {
306
+ const colors = useColors();
307
+ const [focused, _setFocused] = useState(false);
308
+ const [showPassword, setShowPassword] = useState(false);
304
309
 
305
- const height = moderateScale(
306
- props.multiline ? 50 + (props.numberOfLines || 1) * 18 : 50
307
- );
310
+ const height = moderateScale(
311
+ multiline ? 50 + (props.numberOfLines || 1) * 18 : 50
312
+ );
308
313
 
309
- const setFocused = (value: boolean) => {
310
- _setFocused(value);
311
- };
314
+ const setFocused = (value: boolean) => {
315
+ _setFocused(value);
316
+ };
312
317
 
313
- const styles: any = ScaledSheet.create({
314
- root: {
315
- marginBottom: gutterBottom + "@vs",
316
- ...style,
317
- },
318
- container: {
319
- height: height,
320
- overflow: "hidden",
321
- flexDirection: "row",
322
- borderColor: error
323
- ? colors.error.main
324
- : focused
325
- ? colors[color].main
326
- : colors.white[5],
327
- borderWidth: error ? 1 : focused ? 2 : 1,
328
- width: "100%",
329
- borderRadius: rounded ? 30 : 10,
330
- alignItems: "center",
331
- ...inputStyles,
332
- },
333
- input: {
334
- fontSize: "14@s",
335
- flex: 1,
336
- alignSelf: "stretch",
337
- paddingLeft: moderateScale(10),
338
- paddingRight: moderateScale(10),
339
- color: colors.dark.main,
340
- zIndex: 10,
341
- // backgroundColor: "#284",
342
- },
343
- inputText: {
344
- fontSize: "14@ms",
345
- color: colors.dark.main,
346
- paddingLeft: moderateScale(10),
347
- },
348
- placeholder: {
349
- fontSize: "14@ms",
350
- color: colors.textSecondary.main,
351
- paddingLeft: moderateScale(10),
352
- },
353
- label: {},
354
- helperText: {
355
- paddingHorizontal: "15@s",
356
- color: focused ? colors[color].dark : "#fffa",
357
- paddingTop: "4@ms",
358
- },
359
- error: {
360
- paddingLeft: 10,
361
- paddingRight: 10,
362
- paddingTop: 5,
363
- flexDirection: "row",
364
- alignItems: "center",
365
- },
366
- errorText: {
367
- fontSize: 12,
368
- marginLeft: 10,
369
- },
370
- });
371
- const formProps: any =
372
- type === "email"
373
- ? {
374
- textContentType: "emailAddress",
375
- keyboardType: "email-address",
376
- autoCapitalize: "none",
377
- autoCompleteType: "email",
378
- }
379
- : type === "number"
380
- ? {
381
- keyboardType: "numeric",
382
- }
383
- : type === "tel"
384
- ? {
385
- textContentType: "telephoneNumber",
386
- keyboardType: "phone-pad",
387
- }
388
- : type === "search"
389
- ? {
390
- keyboardType: "web-search",
391
- returnKeyType: "search",
392
- autoCapitalize: "none",
393
- }
394
- : type === "password"
395
- ? {
396
- secureTextEntry: !showPassword,
397
- autoCompleteType: "password",
398
- autoCapitalize: "none",
399
- textContentType: "password",
400
- }
401
- : {};
402
- return (
403
- <>
404
- <View style={styles.root}>
405
- {label && (
406
- <Typography variant="body1" color="textSecondary" gutterBottom={7}>
407
- {label}
408
- </Typography>
409
- )}
410
- <TouchableOpacity
411
- onPress={() => setFocused(true)}
412
- style={styles.container}
413
- >
414
- {start}
415
-
416
- {options ? (
417
- <>
418
- {value ? (
419
- <Typography style={styles.inputText}>
420
- {options.find((cur) => cur.value === value)?.label}
421
- </Typography>
422
- ) : (
423
- <Typography style={styles.placeholder}>
424
- {placeholder}
425
- </Typography>
426
- )}
427
- <Ionicons
428
- name="chevron-down"
429
- size={24}
430
- style={{ marginLeft: "auto", marginRight: 15 }}
431
- color={colors.dark.light}
432
- />
433
- </>
434
- ) : (
435
- <TextInput
436
- onFocus={() => {
437
- onFocus();
438
- setFocused(true);
439
- }}
440
- onBlur={() => {
441
- onBlur();
442
- setFocused(false);
443
- }}
444
- value={value}
445
- onChangeText={onChangeText}
446
- key={showPassword ? "show" : "hide"}
447
- keyboardType={keyboardType}
448
- placeholderTextColor={colors.textSecondary.main}
449
- editable={!disabled}
450
- placeholder={placeholder}
451
- selectTextOnFocus={!disabled}
452
- onSubmitEditing={onSubmitEditing}
453
- {...formProps}
454
- {...props}
455
- style={styles.input}
456
- />
318
+ const styles: any = ScaledSheet.create({
319
+ root: {
320
+ marginBottom: gutterBottom + "@vs",
321
+ ...style,
322
+ },
323
+ container: {
324
+ height: height,
325
+ overflow: "hidden",
326
+ flexDirection: "row",
327
+ borderColor: error
328
+ ? colors.error.main
329
+ : focused
330
+ ? colors[color].main
331
+ : colors.white[4],
332
+ borderWidth: error ? 1 : focused ? 2 : 1,
333
+ width: "100%",
334
+ borderRadius: rounded ? 30 : 10,
335
+ alignItems: multiline ? "flex-start" : "center",
336
+ paddingVertical: multiline ? 10 : 0,
337
+ ...inputStyles,
338
+ },
339
+ input: {
340
+ fontSize: "14@s",
341
+ flex: 1,
342
+ alignSelf: "stretch",
343
+ paddingLeft: moderateScale(10),
344
+ paddingRight: moderateScale(10),
345
+ color: colors.dark.main,
346
+ zIndex: 10,
347
+ // backgroundColor: "#284",
348
+ },
349
+ inputText: {
350
+ fontSize: "14@ms",
351
+ color: colors.dark.main,
352
+ paddingLeft: moderateScale(10),
353
+ },
354
+ placeholder: {
355
+ fontSize: "14@ms",
356
+ color: colors.textSecondary.light,
357
+ paddingLeft: moderateScale(10),
358
+ },
359
+ label: {},
360
+ helperText: {
361
+ paddingHorizontal: "15@s",
362
+ color: focused ? colors[color].dark : "#fffa",
363
+ paddingTop: "4@ms",
364
+ },
365
+ error: {
366
+ paddingLeft: 10,
367
+ paddingRight: 10,
368
+ paddingTop: 5,
369
+ flexDirection: "row",
370
+ alignItems: "center",
371
+ },
372
+ errorText: {
373
+ fontSize: 12,
374
+ marginLeft: 10,
375
+ },
376
+ });
377
+ const formProps: any =
378
+ type === "email"
379
+ ? {
380
+ textContentType: "emailAddress",
381
+ keyboardType: "email-address",
382
+ autoCapitalize: "none",
383
+ autoCompleteType: "email",
384
+ }
385
+ : type === "number"
386
+ ? {
387
+ keyboardType: "numeric",
388
+ }
389
+ : type === "tel"
390
+ ? {
391
+ textContentType: "telephoneNumber",
392
+ keyboardType: "phone-pad",
393
+ }
394
+ : type === "search"
395
+ ? {
396
+ keyboardType: "web-search",
397
+ returnKeyType: "search",
398
+ autoCapitalize: "none",
399
+ }
400
+ : type === "password"
401
+ ? {
402
+ secureTextEntry: !showPassword,
403
+ autoCompleteType: "password",
404
+ autoCapitalize: "none",
405
+ textContentType: "password",
406
+ }
407
+ : {};
408
+ return (
409
+ <>
410
+ <View style={styles.root}>
411
+ {label && (
412
+ <Typography variant="body1" color="textSecondary" gutterBottom={7}>
413
+ {label}
414
+ </Typography>
457
415
  )}
416
+ <TouchableOpacity
417
+ onPress={() => setFocused(true)}
418
+ style={styles.container}
419
+ >
420
+ <View style={{ marginTop: multiline ? 5 : 0 }}>{start}</View>
458
421
 
459
- {end ? (
460
- <View style={{ marginRight: 20 }}>{end}</View>
461
- ) : (
462
- type === "password" && (
463
- <TouchableOpacity
464
- style={{ marginRight: 20 }}
465
- onPress={() => setShowPassword(!showPassword)}
466
- >
422
+ {options ? (
423
+ <>
424
+ {value ? (
425
+ <Typography style={styles.inputText}>
426
+ {options.find((cur) => cur.value === value)?.label}
427
+ </Typography>
428
+ ) : (
429
+ <Typography style={styles.placeholder}>
430
+ {placeholder}
431
+ </Typography>
432
+ )}
467
433
  <Ionicons
468
- name={showPassword ? "eye-outline" : "eye-off-outline"}
434
+ name="chevron-down"
469
435
  size={24}
470
- color={colors.textSecondary.main}
436
+ style={{ marginLeft: "auto", marginRight: 15 }}
437
+ color={colors.dark.light}
471
438
  />
472
- </TouchableOpacity>
473
- )
474
- )}
475
- </TouchableOpacity>
476
- {helperText && (
477
- <Typography
478
- color="textSecondary"
479
- style={styles.helperText}
480
- variant="caption"
481
- >
482
- {helperText}
483
- </Typography>
484
- )}
485
- {error && (
486
- <View style={styles.error}>
487
- <MaterialIcons name="error" color={colors.error.main} size={16} />
488
- <Typography style={styles.errorText} color="error">
489
- {error}
439
+ </>
440
+ ) : (
441
+ <TextInput
442
+ ref={ref}
443
+ onFocus={() => {
444
+ onFocus();
445
+ setFocused(true);
446
+ }}
447
+ onBlur={() => {
448
+ onBlur();
449
+ setFocused(false);
450
+ }}
451
+ value={value}
452
+ onChangeText={onChangeText}
453
+ key={showPassword ? "show" : "hide"}
454
+ keyboardType={keyboardType}
455
+ placeholderTextColor={colors.textSecondary.light}
456
+ editable={!disabled}
457
+ placeholder={placeholder}
458
+ selectTextOnFocus={!disabled}
459
+ onSubmitEditing={onSubmitEditing}
460
+ multiline={multiline}
461
+ extAlignVertical={multiline ? "top" : "center"}
462
+ {...formProps}
463
+ {...props}
464
+ style={styles.input}
465
+ />
466
+ )}
467
+
468
+ {end ? (
469
+ <View style={{ marginRight: 20 }}>{end}</View>
470
+ ) : (
471
+ type === "password" && (
472
+ <TouchableOpacity
473
+ style={{ marginRight: 20 }}
474
+ onPress={() => setShowPassword(!showPassword)}
475
+ >
476
+ <Ionicons
477
+ name={showPassword ? "eye-outline" : "eye-off-outline"}
478
+ size={24}
479
+ color={colors.textSecondary.main}
480
+ />
481
+ </TouchableOpacity>
482
+ )
483
+ )}
484
+ </TouchableOpacity>
485
+ {helperText && (
486
+ <Typography
487
+ color="textSecondary"
488
+ style={styles.helperText}
489
+ variant="caption"
490
+ >
491
+ {helperText}
490
492
  </Typography>
491
- </View>
493
+ )}
494
+ {error && (
495
+ <View style={styles.error}>
496
+ <MaterialIcons name="error" color={colors.error.main} size={16} />
497
+ <Typography style={styles.errorText} color="error">
498
+ {error}
499
+ </Typography>
500
+ </View>
501
+ )}
502
+ </View>
503
+ {options && (
504
+ <SelectMenu
505
+ options={options}
506
+ value={value}
507
+ open={focused}
508
+ onClose={() => setFocused(false)}
509
+ label={label}
510
+ helperText={helperText}
511
+ onChange={onChangeText!}
512
+ />
492
513
  )}
493
- </View>
494
- {options && (
495
- <SelectMenu
496
- options={options}
497
- value={value}
498
- open={focused}
499
- onClose={() => setFocused(false)}
500
- label={label}
501
- helperText={helperText}
502
- onChange={onChangeText!}
503
- />
504
- )}
505
- </>
506
- );
507
- };
514
+ </>
515
+ );
516
+ }
517
+ );
508
518
 
509
519
  export default TextField;
@@ -15,7 +15,6 @@ const Typography: React.FC<TypographyProps> = forwardRef(
15
15
  variant = "body1",
16
16
  align = "left",
17
17
  gutterBottom = 0,
18
- numberOfLines,
19
18
  adjustsFontSizeToFit,
20
19
  fontWeight = 400,
21
20
  fontFamily, // NEW PROP ADDED
@@ -52,7 +51,6 @@ const Typography: React.FC<TypographyProps> = forwardRef(
52
51
  return (
53
52
  <Text
54
53
  ref={ref as any}
55
- numberOfLines={numberOfLines}
56
54
  adjustsFontSizeToFit={adjustsFontSizeToFit}
57
55
  style={[styles.text, style]} // Ensures external styles are applied
58
56
  {...props}
@@ -1,10 +1,12 @@
1
1
  type configTypes = {
2
2
  GOOGLE_MAP_API_KEY?: string;
3
3
  DEFAULT_FONT_FAMILY?: string;
4
+ EDGE_TO_EDGE?: boolean;
4
5
  };
5
6
 
6
7
  let config: configTypes = {
7
8
  GOOGLE_MAP_API_KEY: "",
9
+ EDGE_TO_EDGE: false,
8
10
  };
9
11
 
10
12
  export function setConfig(key: configTypes): void {
@@ -7,6 +7,7 @@ type configProps = {
7
7
  googleMapApiKey?: string;
8
8
  colors?: extraColorTypes;
9
9
  fontFamily?: string;
10
+ edgeToEdge?: boolean;
10
11
  };
11
12
 
12
13
  export function initialize(config: configProps): void {
@@ -14,6 +15,7 @@ export function initialize(config: configProps): void {
14
15
  setConfig({
15
16
  GOOGLE_MAP_API_KEY: config.googleMapApiKey,
16
17
  DEFAULT_FONT_FAMILY: config.fontFamily,
18
+ EDGE_TO_EDGE: config.edgeToEdge ?? false,
17
19
  });
18
20
  if (config.colors) setExtraColors(config.colors);
19
21
  } catch (error) {
@@ -5,6 +5,7 @@ import React, { createContext, useEffect, useReducer } from "react";
5
5
  import { Platform, useColorScheme } from "react-native";
6
6
  import { SafeAreaProvider } from "react-native-safe-area-context";
7
7
  import FlashMessage from "../Components/FlashMessage";
8
+ import { getConfig } from "../config/KeyManager";
8
9
  import { useColors, useTheme } from "../hooks";
9
10
  import {
10
11
  ThemeActionTypes,
@@ -41,9 +42,10 @@ const ConfigureSystemUI = () => {
41
42
  const colors = useColors();
42
43
 
43
44
  useEffect(() => {
45
+ const config = getConfig();
44
46
  if (colors) {
45
47
  SystemUI.setBackgroundColorAsync(colors.white[1]);
46
- if (Platform.OS === "android") {
48
+ if (Platform.OS === "android" && !config.EDGE_TO_EDGE) {
47
49
  NavigationBar.setBackgroundColorAsync(colors.white[1]);
48
50
  if (theme === "dark") {
49
51
  NavigationBar.setButtonStyleAsync("light");
package/src/types.ts CHANGED
@@ -2,7 +2,6 @@ import { ReactNode } from "react";
2
2
  import {
3
3
  NativeScrollEvent,
4
4
  NativeSyntheticEvent,
5
- Text,
6
5
  TextInputProps,
7
6
  TextProps,
8
7
  TextStyle,
@@ -79,14 +78,7 @@ export interface AvatarProps {
79
78
  size?: number;
80
79
  style?: ViewStyle;
81
80
  }
82
- export interface AnimatorProps {
83
- style?: ViewStyle;
84
- duration?: number;
85
- children: ReactNode;
86
- delay?: number;
87
- animationType?: "easeInEaseOut" | "linear" | "spring";
88
- type?: "fade" | "slideInLeft" | "slideInRight" | "slideInUp" | "slideInDown";
89
- }
81
+
90
82
  export interface ButtonProps {
91
83
  color?: colorTypes;
92
84
  variant?: "text" | "outlined" | "contained";
@@ -145,6 +137,7 @@ export interface IconButtonProps {
145
137
 
146
138
  export type locatorLocation = {
147
139
  description: string;
140
+ formatted_address?: string;
148
141
  longitude: number;
149
142
  latitude: number;
150
143
  };
@@ -324,3 +317,58 @@ export interface DividerProps {
324
317
  style?: ViewStyle;
325
318
  height?: number;
326
319
  }
320
+
321
+ export type AnimationType =
322
+ | "fade"
323
+ | "grow"
324
+ | "slide"
325
+ | "blink"
326
+ | "float"
327
+ | "roll"
328
+ | "thrownup";
329
+
330
+ // Base props that are common to all animations
331
+ interface BaseAnimatorProps {
332
+ children: ReactNode;
333
+ duration?: number;
334
+ delay?: number;
335
+ closeAfter?: number | null;
336
+ style?: ViewStyle;
337
+ }
338
+
339
+ // Type-specific animation props using discriminated unions
340
+ export type AnimatorProps =
341
+ | (BaseAnimatorProps & {
342
+ type: "fade";
343
+ // No additional props for fade animation
344
+ })
345
+ | (BaseAnimatorProps & {
346
+ type: "grow";
347
+ initialScale?: number;
348
+ })
349
+ | (BaseAnimatorProps & {
350
+ type: "slide";
351
+ direction?: "up" | "down" | "left" | "right";
352
+ initialValue?: number;
353
+ })
354
+ | (BaseAnimatorProps & {
355
+ type: "blink";
356
+ blinkDuration?: number;
357
+ minOpacity?: number;
358
+ maxOpacity?: number;
359
+ })
360
+ | (BaseAnimatorProps & {
361
+ type: "float";
362
+ closeDuration?: number;
363
+ floatDistance?: number;
364
+ floatDuration?: number;
365
+ })
366
+ | (BaseAnimatorProps & {
367
+ type: "roll";
368
+ initialTranslateY?: number;
369
+ initialRotate?: string;
370
+ })
371
+ | (BaseAnimatorProps & {
372
+ type: "thrownup";
373
+ // No additional props for thrownup animation
374
+ });
@@ -1,43 +0,0 @@
1
- import { useFocusEffect } from "@react-navigation/native";
2
- import React, { FC, useCallback, useState } from "react";
3
- import { LayoutAnimation, View } from "react-native";
4
- import { ScaledSheet } from "react-native-size-matters";
5
- import { AnimatorProps } from "../types";
6
-
7
- export const Animator: FC<AnimatorProps> = ({
8
- style = {},
9
- duration = 500,
10
- children,
11
- delay = 100,
12
- animationType = "easeInEaseOut",
13
- type = "fade",
14
- }) => {
15
- const [play, setPlay] = useState(false);
16
- const toggleAnimation = () => {
17
- setPlay(false);
18
-
19
- setTimeout(() => {
20
- LayoutAnimation.configureNext({
21
- ...LayoutAnimation.Presets[animationType],
22
- duration,
23
- });
24
- setPlay(true);
25
- }, delay);
26
- };
27
- const styles = ScaledSheet.create({
28
- root: {
29
- opacity: play ? 1 : 0,
30
- left: type === "slideInLeft" ? (!play ? -200 : 0) : undefined,
31
- right: type === "slideInRight" ? (!play ? -200 : 0) : undefined,
32
- bottom: type === "slideInUp" ? (!play ? -100 : 0) : undefined,
33
- top: type === "slideInDown" ? (!play ? -100 : 0) : undefined,
34
- ...style,
35
- },
36
- });
37
- useFocusEffect(
38
- useCallback(() => {
39
- toggleAnimation();
40
- }, [])
41
- );
42
- return <View style={styles.root}>{play && children}</View>;
43
- };