gbs-add-block 0.0.27 → 0.0.29

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbs-add-block",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "React Component Library",
5
5
  "files": [
6
6
  "index.js",
@@ -5,10 +5,10 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React, { ButtonHTMLAttributes } from "react";
8
+ import React, { ButtonHTMLAttributes, ReactNode } from "react";
9
9
 
10
10
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
11
- children?: any;
11
+ children?: ReactNode;
12
12
  buttonClass?: string;
13
13
  }
14
14
 
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Copyright (c) Grampro Business Services and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
1
8
  import React, { InputHTMLAttributes } from "react";
2
9
 
3
10
  export const Checkbox = ({
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Copyright (c) Grampro Business Services and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
1
8
  import React, { useEffect } from "react";
2
9
  import Icon from "../icon/Icon";
3
10
  import { moon, sun } from "../icon/iconPaths";
@@ -45,4 +52,4 @@ export const DarkMode = () => {
45
52
  )}
46
53
  </button>
47
54
  );
48
- }
55
+ };
@@ -1,33 +1,69 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
+ import { validateEmail, validatePhoneNumber } from "./helperFunctions";
2
3
  import { Input } from "../input";
4
+ import { FormItem } from "./types";
3
5
 
4
- export default function InputHandles({
6
+ interface InputHandlesProps {
7
+ item?: FormItem;
8
+ requirementError: string[];
9
+ setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
10
+ }
11
+
12
+ const InputHandles = ({
5
13
  item,
6
14
  requirementError,
7
15
  setRequirementError,
8
- }: any) {
16
+ }: InputHandlesProps) => {
17
+ const [inputError, setInputError] = useState<string | null>(null);
18
+
19
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
20
+ const { value } = event.target;
21
+
22
+ setRequirementError &&
23
+ setRequirementError((prevErrors: string[]) =>
24
+ prevErrors.filter((error) => error !== item?.name)
25
+ );
26
+
27
+ // Validation based on input type
28
+ if (item?.type === "email") {
29
+ if (!validateEmail(value)) {
30
+ setInputError("Invalid email format");
31
+ } else {
32
+ setInputError(null);
33
+ }
34
+ } else if (item?.type === "tel") {
35
+ if (!validatePhoneNumber(value)) {
36
+ setInputError("Invalid phone number. Must be 10 digits.");
37
+ } else {
38
+ setInputError(null);
39
+ }
40
+ }
41
+ };
42
+
9
43
  return (
10
44
  <div className="w-full">
11
- {item.label && (
45
+ {item?.label && (
12
46
  <label htmlFor={item.name} className="font-medium text-sm">
13
47
  {item.label}
14
48
  </label>
15
49
  )}
16
50
  <Input
17
- type={item.type}
18
- name={item.name}
19
- placeholder={item.placeholder || ""}
20
- error={
21
- requirementError.includes(item.name)
22
- ? `${item.name} is required`
23
- : undefined
24
- }
25
- onChange={() =>
26
- setRequirementError((prevErrors: any) =>
27
- prevErrors.filter((errorName: any) => errorName !== item.name)
28
- )
29
- }
51
+ type={item?.type}
52
+ name={item?.name}
53
+ placeholder={item?.placeholder || ""}
54
+ onChange={handleChange}
55
+ className={`border rounded p-2 w-full text-black ${
56
+ inputError || (item?.name && requirementError.includes(item?.name))
57
+ ? "border-red-500"
58
+ : "border-gray-300"
59
+ }`}
30
60
  />
61
+ {item?.name && requirementError.includes(item.name) && (
62
+ <p className="text-red-500 text-xs">{`${item?.name} is required`}</p>
63
+ )}
64
+ {inputError && <p className="text-red-500 text-xs">{inputError}</p>}
31
65
  </div>
32
66
  );
33
- }
67
+ };
68
+
69
+ export default InputHandles;
@@ -1,14 +1,22 @@
1
1
  import React from "react";
2
2
  import { Select } from "../select";
3
+ import { FormItem } from "./types";
4
+
5
+ interface SelectHandlesProps {
6
+ item?: FormItem;
7
+ requirementError: string[];
8
+ setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
9
+ formRef?: React.RefObject<HTMLFormElement>;
10
+ }
3
11
 
4
12
  export default function SelectHandles({
5
13
  item,
6
14
  requirementError,
7
15
  setRequirementError,
8
16
  formRef,
9
- }: any) {
17
+ }: SelectHandlesProps) {
10
18
  const handleSelect = (value: string, key: string) => {
11
- if (formRef.current) {
19
+ if (formRef && formRef.current) {
12
20
  const hiddenInput = formRef.current.querySelector(
13
21
  `input[name="${key}"]`
14
22
  ) as HTMLInputElement;
@@ -27,22 +35,23 @@ export default function SelectHandles({
27
35
 
28
36
  return (
29
37
  <div className="w-full">
30
- {item.label && (
38
+ {item?.label && (
31
39
  <label htmlFor={item.name} className="font-medium text-sm">
32
40
  {item.label}
33
41
  </label>
34
42
  )}
35
43
  <Select
36
- name={item.name}
37
- items={item.options}
44
+ name={item?.name}
45
+ items={item?.options}
38
46
  onSelect={(value: string) => {
39
- handleSelect(value, item.key);
40
- setRequirementError((prevErrors: any) =>
41
- prevErrors.filter((errorName: any) => errorName !== item.name)
42
- );
47
+ item?.key && handleSelect(value, item.key);
48
+ setRequirementError &&
49
+ setRequirementError((prevErrors: any) =>
50
+ prevErrors.filter((errorName: any) => errorName !== item?.name)
51
+ );
43
52
  }}
44
53
  error={
45
- requirementError.includes(item.name)
54
+ item?.name && requirementError.includes(item.name)
46
55
  ? `${item.name} is required`
47
56
  : undefined
48
57
  }
@@ -0,0 +1,9 @@
1
+ export const validateEmail = (email: string) => {
2
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3
+ return emailRegex.test(email);
4
+ };
5
+
6
+ export const validatePhoneNumber = (phone: string) => {
7
+ const phoneRegex = /^[0-9]{10}$/;
8
+ return phoneRegex.test(phone);
9
+ };
@@ -1,9 +1,16 @@
1
+ /**
2
+ * Copyright (c) Grampro Business Services and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
1
8
  import React, { useRef, useState } from "react";
2
- import { Button } from "../button";
3
9
  import InputHandles from "./InputHandles";
4
10
  import SelectHandles from "./SelectHandles";
11
+ import { FormItem, FormRendererProps } from "./types";
5
12
 
6
- const FormRenderer = ({ onSubmit, sourceData }: any) => {
13
+ const FormRenderer = ({ onSubmit, sourceData }: FormRendererProps) => {
7
14
  const formRef = useRef<HTMLFormElement>(null);
8
15
  const [requirementError, setRequirementError] = useState<string[]>([]);
9
16
 
@@ -12,8 +19,8 @@ const FormRenderer = ({ onSubmit, sourceData }: any) => {
12
19
 
13
20
  const requirementErrorItems: string[] = [];
14
21
 
15
- sourceData.forEach((item: any) => {
16
- if (item.required) {
22
+ sourceData?.forEach((item: FormItem) => {
23
+ if (item.required && item.name) {
17
24
  const field = formRef.current?.querySelector(
18
25
  `[name="${item.name}"]`
19
26
  ) as HTMLInputElement | null;
@@ -29,14 +36,14 @@ const FormRenderer = ({ onSubmit, sourceData }: any) => {
29
36
  if (requirementErrorItems.length > 0) return;
30
37
 
31
38
  const formData = new FormData(formRef.current as HTMLFormElement);
32
- onSubmit(formData);
39
+ if (onSubmit) onSubmit(formData);
33
40
  };
34
41
 
35
42
  return (
36
43
  <form ref={formRef} onSubmit={handleSubmit} className="w-96">
37
- {sourceData?.length > 0 ? (
44
+ {sourceData && sourceData?.length > 0 ? (
38
45
  <div className="flex flex-col items-start text-left gap-4">
39
- {sourceData.map((item: any, index: number) => {
46
+ {sourceData.map((item: FormItem, index: number) => {
40
47
  switch (item.component) {
41
48
  case "input":
42
49
  return (
@@ -62,12 +69,12 @@ const FormRenderer = ({ onSubmit, sourceData }: any) => {
62
69
  case "button":
63
70
  return (
64
71
  <div key={index} className="w-full mt-2">
65
- <Button
66
- type={item.type}
67
- className="w-full bg-black text-white py-2 rounded-xl hover:bg-gray-800"
72
+ <button
73
+ type={item.button_type}
74
+ className="w-full bg-black text-white py-2 rounded-xl hover:bg-gray-800 dark:hover:bg-gray-300 dark:bg-white dark:text-black"
68
75
  >
69
76
  {item.value}
70
- </Button>
77
+ </button>
71
78
  </div>
72
79
  );
73
80
 
@@ -0,0 +1,17 @@
1
+ export type FormItem = {
2
+ name?: string;
3
+ component?: string;
4
+ type?: string;
5
+ required?: boolean;
6
+ placeholder?: string;
7
+ options?: { value: string; label: string }[];
8
+ value?: string;
9
+ label?: string;
10
+ button_type?: "button" | "submit" | "reset";
11
+ key?: string;
12
+ };
13
+
14
+ export type FormRendererProps = {
15
+ onSubmit?: (formData: FormData) => void;
16
+ sourceData?: FormItem[] | undefined;
17
+ };
@@ -15,21 +15,24 @@ export const Input = ({
15
15
  OTPField = false,
16
16
  OTPValue = "",
17
17
  OTPLength = 4,
18
- OTPClass = "w-8 h-10 m-1 border border-gray-600 rounded-lg text-center",
18
+ OTPClass = "w-8 h-10 m-1 border border-gray-600 rounded-lg text-center text-black",
19
19
  onOTPValueChange,
20
20
  error = undefined,
21
21
  ...props
22
22
  }: InputProps) => {
23
23
  const [otpValues, setOtpValues] = useState(new Array(OTPLength).fill(""));
24
24
  const [showPassword, setShowPassword] = useState(false);
25
- const inputRefs = useRef<any>([]);
25
+ const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
26
26
 
27
27
  const defaultClass = `bg-gray-100 p-2 rounded-lg ${
28
28
  error ? "border border-red-600" : ""
29
29
  }`;
30
30
 
31
31
  // This will update the OTP Field Value
32
- const updateOtpValue = (index: number, e: any) => {
32
+ const updateOtpValue = (
33
+ index: number,
34
+ e: React.ChangeEvent<HTMLInputElement>
35
+ ) => {
33
36
  e.preventDefault();
34
37
  const input = e.target;
35
38
  if (input) {
@@ -37,7 +40,7 @@ export const Input = ({
37
40
  newOtpValues[index] = input.value;
38
41
  setOtpValues(newOtpValues);
39
42
  if (index < OTPLength - 1 && input.value) {
40
- inputRefs.current[index + 1].focus();
43
+ inputRefs.current[index + 1]?.focus();
41
44
  }
42
45
  OTPValue = newOtpValues.join("");
43
46
  if (onOTPValueChange) onOTPValueChange(OTPValue);
@@ -45,13 +48,16 @@ export const Input = ({
45
48
  };
46
49
 
47
50
  // Function for handling keyboard navigation in OTP Field
48
- const handleKeydown = (index: number, e: any) => {
51
+ const handleKeydown = (
52
+ index: number,
53
+ e: React.KeyboardEvent<HTMLInputElement>
54
+ ) => {
49
55
  if (e.key === "Backspace" && otpValues[index] === "" && index > 0) {
50
- inputRefs.current[index - 1].focus();
56
+ inputRefs.current[index - 1]?.focus();
51
57
  } else if (e.key === "ArrowLeft" && index > 0) {
52
- inputRefs.current[index - 1].focus();
58
+ inputRefs.current[index - 1]?.focus();
53
59
  } else if (e.key === "ArrowRight" && index < OTPLength - 1) {
54
- inputRefs.current[index + 1].focus();
60
+ inputRefs.current[index + 1]?.focus();
55
61
  }
56
62
  };
57
63
 
@@ -65,7 +71,10 @@ export const Input = ({
65
71
  {!OTPField ? (
66
72
  <div className="text-input-container w-full relative">
67
73
  <input
68
- className={twMerge(defaultClass, "w-full focus:outline-blue-400")}
74
+ className={twMerge(
75
+ defaultClass,
76
+ "w-full text-black focus:outline-blue-400"
77
+ )}
69
78
  {...props}
70
79
  type={
71
80
  props.type === "password" && showPassword ? "text" : props.type
@@ -18,11 +18,11 @@ import React, {
18
18
  import Icon from "../icon/Icon";
19
19
  import { check, search, upDown, x } from "../icon/iconPaths";
20
20
  import { getSourceData } from "../utils";
21
- import type { ItemsProps, SelectProps } from "./types";
21
+ import type { ItemsProps, SelectHandle, SelectProps } from "./types";
22
22
  import { selectStyle } from "./style";
23
23
  import { popUp, primary } from "../globalStyle";
24
24
 
25
- const Select = forwardRef<any, SelectProps>((props, ref) => {
25
+ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
26
26
  const {
27
27
  id = "",
28
28
  name = "",
@@ -227,5 +227,7 @@ const Select = forwardRef<any, SelectProps>((props, ref) => {
227
227
  );
228
228
  });
229
229
 
230
+ Select.displayName = "Select";
231
+
230
232
  const MemoizedSelect = memo(Select);
231
233
  export { MemoizedSelect as Select };
@@ -11,7 +11,16 @@ export type SelectProps = {
11
11
  items?: ItemsProps[] | string;
12
12
  lazy?: boolean;
13
13
  showSearch?: boolean;
14
- onSelect?: any;
14
+ onSelect?: (selectedItem: string) => void;
15
15
  selectedItem?: string;
16
- onFiltering?: any;
16
+ onFiltering?: (searchTerm: string) => void;
17
+ };
18
+
19
+ export type SelectHandle = {
20
+ workingDataSource: ItemsProps[];
21
+ clearSelected: () => void;
22
+ togglePopover: (e: React.MouseEvent) => void;
23
+ getSelectItems: (itemsApi: string) => Promise<void>;
24
+ selectedDisplay: string;
25
+ selected: string | undefined;
17
26
  };
@@ -4,7 +4,7 @@ export default function Fallback(props: any) {
4
4
  const { component } = props;
5
5
  return (
6
6
  <div>
7
- <p>oops {component} failed!!</p>
7
+ <p>Oops {component} failed!!</p>
8
8
  <button>Raise an Issue</button>
9
9
  </div>
10
10
  );