@hoddy-ui/core 1.1.0 → 1.1.1

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/next/index.ts CHANGED
@@ -25,6 +25,7 @@ export * from "../src/Components/OTPInput";
25
25
  // export * from "../src/config";
26
26
  export * from "../src/hooks";
27
27
  export * from "../src/theme";
28
+ export * from "../src/types";
28
29
 
29
30
  const HoddyUI = {
30
31
  initialize: initialize,
package/next/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoddy-ui/next",
3
- "version": "2.0.34",
3
+ "version": "2.0.47",
4
4
  "description": "Core rich react native components written in typescript, with support for expo-router",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoddy-ui/core",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Core rich react native components written in typescript",
5
5
  "main": "index.ts",
6
6
  "repository": {
@@ -12,11 +12,14 @@ import { LocatorProps } from "../types";
12
12
  import { getConfig } from "../config/KeyManager";
13
13
  import Typography from "./Typography";
14
14
 
15
- type predictionType = {
15
+ export type predictionType = {
16
16
  id: string;
17
17
  description: string;
18
18
  };
19
- export const getPredictionsFromCoords = async (coords: any) => {
19
+ export const getPredictionsFromCoords = async (coords: {
20
+ latitude: number;
21
+ longitude: number;
22
+ }) => {
20
23
  const { GOOGLE_MAP_API_KEY } = getConfig();
21
24
 
22
25
  if (!GOOGLE_MAP_API_KEY)
@@ -44,6 +47,45 @@ export const getPredictionsFromCoords = async (coords: any) => {
44
47
  return p;
45
48
  };
46
49
 
50
+ export const getPredictionsFromQuery = async (
51
+ query: string,
52
+ country: string
53
+ ) => {
54
+ const { GOOGLE_MAP_API_KEY } = getConfig();
55
+ const endpoint = `https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${query}&components=country:${country}&radius=20000&key=${GOOGLE_MAP_API_KEY}`;
56
+ const res = await (await fetch(endpoint)).json();
57
+
58
+ const p = [];
59
+ for (let key in res.predictions) {
60
+ const { description, place_id } = res.predictions[key];
61
+ p.push({
62
+ description,
63
+ id: place_id,
64
+ });
65
+ }
66
+ return p;
67
+ };
68
+
69
+ export const getLocationFromPlaceId = async (
70
+ place_id: string
71
+ ): Promise<{
72
+ formatted_address: string;
73
+ geometry: {
74
+ location: {
75
+ lat: number;
76
+ lng: number;
77
+ };
78
+ };
79
+ }> => {
80
+ const { GOOGLE_MAP_API_KEY } = getConfig();
81
+ const res = await (
82
+ await fetch(
83
+ `https://maps.googleapis.com/maps/api/place/details/json?place_id=${place_id}&fields=formatted_address%2Cgeometry&key=${GOOGLE_MAP_API_KEY}`
84
+ )
85
+ ).json();
86
+ return res.result;
87
+ };
88
+
47
89
  export const Locator: React.FC<LocatorProps> = ({
48
90
  variant = "contained",
49
91
  onLocationSelected,
@@ -84,17 +126,8 @@ export const Locator: React.FC<LocatorProps> = ({
84
126
  },
85
127
  });
86
128
  const search = async (query: string) => {
87
- const endpoint = `https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${query}&components=country:${country}&radius=20000&key=${GOOGLE_MAP_API_KEY}`;
88
- const res = await (await fetch(endpoint)).json();
89
- const p = [];
90
- for (let key in res.predictions) {
91
- const { description, place_id } = res.predictions[key];
92
- p.push({
93
- description,
94
- id: place_id,
95
- });
96
- }
97
- setPrediction(p);
129
+ const predictions = await getPredictionsFromQuery(query, country);
130
+ setPrediction(predictions);
98
131
  };
99
132
 
100
133
  const locateMe = () => {
@@ -135,19 +168,14 @@ export const Locator: React.FC<LocatorProps> = ({
135
168
  };
136
169
  const locationPressed = async (loc: predictionType) => {
137
170
  setValue(loc.description);
138
- const res = await (
139
- await fetch(
140
- `https://maps.googleapis.com/maps/api/place/details/json?place_id=${loc.id}&fields=formatted_address%2Cgeometry&key=${GOOGLE_MAP_API_KEY}`
141
- )
142
- ).json();
171
+ const res = await getLocationFromPlaceId(loc.id);
143
172
  onLocationSelected(
144
173
  {
145
- latitude: res.result?.geometry.location.lat,
146
- longitude: res.result?.geometry.location.lng,
147
-
174
+ latitude: res.geometry.location.lat,
175
+ longitude: res.geometry.location.lng,
148
176
  description: loc.description,
149
177
  },
150
- res.result?.formatted_address
178
+ res?.formatted_address
151
179
  );
152
180
  setChanged(false);
153
181
  setPrediction([]);
@@ -58,15 +58,18 @@ export const Popup: React.FC<PopupProps> = ({
58
58
  ...style,
59
59
  },
60
60
  content: {
61
- paddingHorizontal: bare ? undefined : "10@ms",
61
+ paddingHorizontal: bare ? undefined : "15@ms",
62
62
  // flex: 1,
63
63
  },
64
64
  title: {
65
65
  flexDirection: "row",
66
66
  alignItems: "center",
67
- paddingVertical: "5@ms",
68
- paddingHorizontal: "10@ms",
69
- marginBottom: "10@ms",
67
+ justifyContent: "center",
68
+ height: "50@ms",
69
+ },
70
+ titleIcon: {
71
+ position: "absolute",
72
+ left: "15@ms",
70
73
  },
71
74
  backdrop: {
72
75
  position: "absolute",
@@ -131,16 +134,16 @@ export const Popup: React.FC<PopupProps> = ({
131
134
  <View style={styles.container}>
132
135
  {!bare && (
133
136
  <View style={styles.title}>
134
- <IconButton
135
- size={20}
136
- icon="close"
137
- onPress={closeAction}
138
- />
139
- <View style={{ flex: 1 }}>
140
- <Typography color="textSecondary" align="center">
141
- {title}
142
- </Typography>
137
+ <View style={styles.titleIcon}>
138
+ <IconButton
139
+ size={20}
140
+ icon="close"
141
+ onPress={closeAction}
142
+ />
143
143
  </View>
144
+ <Typography align="center" fontWeight={500}>
145
+ {title}
146
+ </Typography>
144
147
  </View>
145
148
  )}
146
149
 
@@ -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}