gbs-add-block 0.0.48 → 0.0.50

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GBS Building Blocks 2.0 (v0.0.48)
1
+ # GBS Building Blocks 2.0 (v0.0.50)
2
2
 
3
3
  Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
4
4
 
@@ -6,10 +6,10 @@ Latest and upgraded version of GBS building blocks with headless UI and removed
6
6
 
7
7
  For detailed documentation on usage and props, Please visit: [Building Block Documentation v2.0](https://blackmax-designs.gitbook.io/building-block-v2.0)
8
8
 
9
- ## What's New 🎉 (Ver 0.0.48)
9
+ ## What's New 🎉 (Ver 0.0.50)
10
10
 
11
+ - Update on form renderer
11
12
  - Refactored Code for Better Readability
12
- - Code Reusablity and hook update
13
13
 
14
14
  ## Authors
15
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbs-add-block",
3
- "version": "0.0.48",
3
+ "version": "0.0.50",
4
4
  "description": "React Component Library",
5
5
  "files": [
6
6
  "index.js",
@@ -11,6 +11,8 @@ const CheckboxHandles = ({
11
11
  }: CheckboxHandlesProps) => {
12
12
  const [checked, setChecked] = useState<boolean>(!!item?.value);
13
13
 
14
+ // We Need this to set the value of the checkbox in the form
15
+ // if the value is not set in the form
14
16
  useEffect(() => {
15
17
  if (item?.name) {
16
18
  handleSelect(checked, item.name);
@@ -40,6 +42,7 @@ const CheckboxHandles = ({
40
42
  <input
41
43
  type="checkbox"
42
44
  checked={checked}
45
+ name={item?.name}
43
46
  onChange={(e) => {
44
47
  const newValue = e.target.checked;
45
48
  setChecked(newValue);
@@ -1,14 +1,6 @@
1
1
  import React from "react";
2
2
  import { DatePicker } from "../../datepicker";
3
- import { FormItem } from "../types";
4
-
5
- interface DatePickerHandlesProps {
6
- item?: FormItem;
7
- requirementError: string[];
8
- setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
9
- formRef?: React.RefObject<HTMLFormElement | null>;
10
- onChangeEvent?: (event: any) => void;
11
- }
3
+ import { DatePickerHandlesProps } from "../types";
12
4
 
13
5
  export default function DatePickerHandles({
14
6
  item,
@@ -1,81 +1,81 @@
1
- import React, { useEffect, useState } from "react";
2
- import { validateEmail, validatePhoneNumber } from "../helperFunctions";
1
+ import React, { useEffect, useState, useCallback } from "react";
2
+ import { validateInput } from "../helperFunctions";
3
3
  import { Input } from "../../input";
4
- import { FieldValue, FormContext, FormItem } from "../types";
4
+ import { InputHandlesProps } from "../types";
5
5
  import { evaluateExpression } from "@grampro/headless-helpers";
6
6
  import { twMerge } from "tailwind-merge";
7
7
 
8
- interface InputHandlesProps {
9
- item?: FormItem;
10
- requirementError: string[];
11
- setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
12
- onChangeEvent?: (event: any) => void;
13
- formRef: React.RefObject<HTMLFormElement | null>;
14
- context: FormContext;
15
- updateContext: (
16
- componentName: string,
17
- fieldName: string,
18
- value: FieldValue
19
- ) => void;
20
- }
21
-
22
- const InputHandles = ({
8
+ const InputHandles: React.FC<InputHandlesProps> = ({
23
9
  item,
24
10
  requirementError,
25
11
  setRequirementError,
26
12
  onChangeEvent,
27
13
  context,
28
14
  updateContext,
29
- }: InputHandlesProps) => {
15
+ }) => {
30
16
  const [inputError, setInputError] = useState<string | null>(null);
31
17
  const [isDisabled, setIsDisabled] = useState<boolean>(false);
32
18
  const [isRequired, setIsRequired] = useState<boolean>(false);
33
19
 
34
- // Initialize context with default values
20
+ // Evaluate expression with memoization
21
+ const evaluateCondition = useCallback(
22
+ (expression: string | boolean | undefined): boolean => {
23
+ if (typeof expression === "string") {
24
+ return evaluateExpression(expression, context);
25
+ }
26
+ return !!expression;
27
+ },
28
+ [context]
29
+ );
30
+
31
+ // Initialize context and handle dynamic states
35
32
  useEffect(() => {
36
33
  if (item?.name && item?.value !== undefined) {
37
34
  updateContext("input", item.name, item.value);
38
35
  }
39
- }, [item?.name, item?.value, updateContext]);
40
36
 
41
- // Handle dynamic disabled/required states expressions
42
- useEffect(() => {
43
- if (typeof item?.disabled === "string") {
44
- setIsDisabled(evaluateExpression(item.disabled, context));
45
- } else if (typeof item?.disabled === "boolean") {
46
- setIsDisabled(item.disabled);
47
- }
37
+ const disabled = evaluateCondition(item?.disabled);
38
+ setIsDisabled(disabled);
48
39
 
49
- if (typeof item?.required === "string") {
50
- setIsRequired(evaluateExpression(item.required, context));
51
- } else if (typeof item?.required === "boolean") {
52
- setIsRequired(item.required);
53
- }
54
- }, [item, context]);
40
+ // Only set required if not disabled
41
+ const required = disabled ? false : evaluateCondition(item?.required);
42
+ setIsRequired(required);
43
+ }, [item, context, evaluateCondition, updateContext]);
55
44
 
56
- const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
57
- const { value } = event.target;
45
+ const handleChange = useCallback(
46
+ (event: React.ChangeEvent<HTMLInputElement>) => {
47
+ const { value } = event.target;
58
48
 
59
- if (item?.name) {
60
- updateContext("input", item.name, value);
49
+ if (item?.name) {
50
+ updateContext("input", item.name, value);
51
+ setRequirementError?.((prev) =>
52
+ prev.filter((error) => error !== item.name)
53
+ );
54
+ }
61
55
 
62
- setRequirementError?.((prevErrors) =>
63
- prevErrors.filter((error) => error !== item.name)
64
- );
65
- }
56
+ const validationError = validateInput(value, item?.type);
57
+ setInputError(validationError);
66
58
 
67
- // Validation based on input type
68
- if (item?.type === "email" && !validateEmail(value)) {
69
- setInputError("Invalid email format");
70
- } else if (item?.type === "tel" && !validatePhoneNumber(value)) {
71
- setInputError("Invalid phone number. Must be 10 digits.");
72
- } else {
73
- setInputError(null);
74
- }
59
+ onChangeEvent?.(event);
60
+ },
61
+ [
62
+ item?.name,
63
+ item?.type,
64
+ updateContext,
65
+ setRequirementError,
66
+ onChangeEvent,
67
+ validateInput,
68
+ ]
69
+ );
75
70
 
76
- // Trigger onChange event
77
- onChangeEvent?.(event);
78
- };
71
+ // Merge input classes
72
+ const inputClassName = twMerge(
73
+ "border rounded-md px-4 py-[6px] w-full text-black",
74
+ inputError || (item?.name && requirementError.includes(item?.name))
75
+ ? "border-red-500"
76
+ : "border-gray-300",
77
+ item?.stepProperty?.customClass?.inputClass
78
+ );
79
79
 
80
80
  return (
81
81
  <div className="w-full">
@@ -88,22 +88,15 @@ const InputHandles = ({
88
88
  <Input
89
89
  type={item?.type}
90
90
  name={item?.name}
91
- placeholder={item?.placeholder || ""}
91
+ placeholder={item?.placeholder ?? ""}
92
92
  onChange={handleChange}
93
- className={twMerge(
94
- `border rounded-md px-4 py-[6px] w-full text-black ${
95
- inputError || (item?.name && requirementError.includes(item?.name))
96
- ? "border-red-500"
97
- : "border-gray-300"
98
- }`,
99
- item?.stepProperty?.customClass?.inputClass
100
- )}
93
+ className={inputClassName}
101
94
  defaultValue={item?.value ?? ""}
102
95
  disabled={isDisabled}
103
96
  required={isRequired}
104
97
  />
105
98
  {item?.name && requirementError.includes(item.name) && (
106
- <p className="text-red-500 text-xs">{`${item?.name} is required`}</p>
99
+ <p className="text-red-500 text-xs">{`${item.name} is required`}</p>
107
100
  )}
108
101
  {inputError && <p className="text-red-500 text-xs">{inputError}</p>}
109
102
  </div>
@@ -1,14 +1,7 @@
1
- import React from "react";
2
- import { FormItem } from "../types";
1
+ import React, { useCallback, useEffect, useState } from "react";
2
+ import { MultiSelectHandlesProps } from "../types";
3
3
  import { MultiSelect } from "../../multiselect";
4
-
5
- interface MultiSelectHandlesProps {
6
- item?: FormItem;
7
- requirementError: string[];
8
- setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
9
- formRef?: React.RefObject<HTMLFormElement | null>;
10
- onChangeEvent?: (event: any) => void;
11
- }
4
+ import { evaluateExpression } from "@grampro/headless-helpers";
12
5
 
13
6
  export default function MultiHandles({
14
7
  item,
@@ -16,7 +9,39 @@ export default function MultiHandles({
16
9
  setRequirementError,
17
10
  formRef,
18
11
  onChangeEvent,
12
+ context,
13
+ updateContext,
19
14
  }: MultiSelectHandlesProps) {
15
+ const [isDisabled, setIsDisabled] = useState<boolean>(false);
16
+ const [isRequired, setIsRequired] = useState<boolean>(false);
17
+
18
+ // Evaluate expression with memoization
19
+ const evaluateCondition = useCallback(
20
+ (expression: string | boolean | undefined): boolean => {
21
+ if (typeof expression === "string") {
22
+ return evaluateExpression(expression, context);
23
+ }
24
+ return !!expression;
25
+ },
26
+ [context]
27
+ );
28
+
29
+ // Initialize context and handle dynamic states
30
+ useEffect(() => {
31
+ if (item?.name && item?.value !== undefined) {
32
+ updateContext("select", item.name, item.value);
33
+ }
34
+
35
+ const disabled = evaluateCondition(item?.disabled);
36
+ console.log("disabled", disabled);
37
+
38
+ setIsDisabled(disabled);
39
+
40
+ // Only set required if not disabled
41
+ const required = disabled ? false : evaluateCondition(item?.required);
42
+ setIsRequired(required);
43
+ }, [item, context, evaluateCondition, updateContext]);
44
+
20
45
  const handleSelect = (value: string[], key: string) => {
21
46
  if (formRef && formRef.current) {
22
47
  const hiddenInput = formRef.current.querySelector(
@@ -42,7 +67,7 @@ export default function MultiHandles({
42
67
  {item?.label && (
43
68
  <label htmlFor={item.name} className="font-medium text-sm">
44
69
  {item.label}
45
- {item.required && <span className="text-red-500">*</span>}
70
+ {isRequired && <span className="text-red-500">*</span>}
46
71
  </label>
47
72
  )}
48
73
  <MultiSelect
@@ -62,6 +87,7 @@ export default function MultiHandles({
62
87
  ? `${item.name} is required`
63
88
  : undefined
64
89
  }
90
+ disabled={isDisabled}
65
91
  />
66
92
  </div>
67
93
  );
@@ -1,24 +1,7 @@
1
- import React, { useState } from "react";
1
+ import React, { useCallback, useEffect, useState } from "react";
2
2
  import { Select } from "../../select";
3
-
4
- interface Option {
5
- value: string;
6
- label: string;
7
- }
8
-
9
- interface SelectHandlesProps {
10
- item?: {
11
- name?: string;
12
- label?: string;
13
- options?: Option[];
14
- value?: string;
15
- required?: boolean;
16
- };
17
- requirementError: string[];
18
- setRequirementError: React.Dispatch<React.SetStateAction<string[]>>;
19
- formRef: React.RefObject<HTMLFormElement | null>;
20
- onChangeEvent?: (event: any) => void;
21
- }
3
+ import { Option, SelectHandlesProps } from "../types";
4
+ import { evaluateExpression } from "@grampro/headless-helpers";
22
5
 
23
6
  export default function SelectHandles({
24
7
  item,
@@ -26,9 +9,41 @@ export default function SelectHandles({
26
9
  setRequirementError,
27
10
  formRef,
28
11
  onChangeEvent,
12
+ context,
13
+ updateContext,
29
14
  }: SelectHandlesProps) {
30
15
  const [options] = useState<Option[]>(item?.options || []);
16
+ const [isDisabled, setIsDisabled] = useState<boolean>(false);
17
+ const [isRequired, setIsRequired] = useState<boolean>(false);
18
+
19
+ // Evaluate expression with memoization
20
+ const evaluateCondition = useCallback(
21
+ (expression: string | boolean | undefined): boolean => {
22
+ if (typeof expression === "string") {
23
+ return evaluateExpression(expression, context);
24
+ }
25
+ return !!expression;
26
+ },
27
+ [context]
28
+ );
29
+
30
+ // Initialize context and handle dynamic states
31
+ useEffect(() => {
32
+ if (item?.name && item?.value !== undefined) {
33
+ updateContext("select", item.name, item.value);
34
+ }
35
+
36
+ const disabled = evaluateCondition(item?.disabled);
37
+ console.log("disabled", disabled);
38
+
39
+ setIsDisabled(disabled);
40
+
41
+ // Only set required if not disabled
42
+ const required = disabled ? false : evaluateCondition(item?.required);
43
+ setIsRequired(required);
44
+ }, [item, context, evaluateCondition, updateContext]);
31
45
 
46
+ // Handle select change event
32
47
  const handleSelect = (value: string | undefined, key: string) => {
33
48
  if (!formRef?.current) return;
34
49
 
@@ -55,7 +70,7 @@ export default function SelectHandles({
55
70
  {item?.label && (
56
71
  <label htmlFor={item.name} className="font-medium text-sm">
57
72
  {item.label}
58
- {item.required && <span className="text-red-500">*</span>}
73
+ {isRequired && <span className="text-red-500">*</span>}
59
74
  </label>
60
75
  )}
61
76
  <Select
@@ -74,6 +89,7 @@ export default function SelectHandles({
74
89
  ? `${item.name} is required`
75
90
  : undefined
76
91
  }
92
+ disabled={isDisabled}
77
93
  />
78
94
  </div>
79
95
  );
@@ -20,3 +20,18 @@ export const formDataToObject = (formData: FormData) => {
20
20
  });
21
21
  return obj;
22
22
  };
23
+
24
+ export const validateInput = (value: string, type?: string): string | null => {
25
+ if (!value) return null;
26
+
27
+ switch (type) {
28
+ case "email":
29
+ return validateEmail(value) ? null : "Invalid email format";
30
+ case "tel":
31
+ return validatePhoneNumber(value)
32
+ ? null
33
+ : "Invalid phone number. Must be 10 digits.";
34
+ default:
35
+ return null;
36
+ }
37
+ };
@@ -1,151 +1,111 @@
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
-
8
- import React, { useRef, useState } from "react";
1
+ import React, { useRef, useState, FormEvent } from "react";
9
2
  import { useFormContext } from "@grampro/headless-helpers";
10
- import { FormElement, FormItem, FormRendererProps } from "./types";
11
3
  import InputHandles from "./componentHandles/InputHandles";
12
4
  import SelectHandles from "./componentHandles/SelectHandles";
13
5
  import MultiHandles from "./componentHandles/MultiHandles";
14
6
  import DatePickerHandles from "./componentHandles/DatePickerHandles";
15
7
  import CheckboxHandles from "./componentHandles/CheckBoxHandles";
8
+ import { FormItem, FormRendererProps } from "./types";
9
+
10
+ // Component mapping
11
+ const COMPONENT_MAP = {
12
+ input: InputHandles,
13
+ select: SelectHandles,
14
+ "multi-select": MultiHandles,
15
+ datepicker: DatePickerHandles,
16
+ checkbox: CheckboxHandles,
17
+ } as const;
18
+
19
+ const validateField = (
20
+ field: HTMLInputElement | null,
21
+ item: FormItem
22
+ ): boolean => {
23
+ if (!item.required || !item.name || field?.disabled) {
24
+ return true;
25
+ }
26
+ // Explicitly check for null and empty value
27
+ if (!field) {
28
+ return false;
29
+ }
30
+ return field.value.trim() !== "";
31
+ };
16
32
 
17
- const FormRenderer = ({
33
+ const FormRenderer: React.FC<FormRendererProps> = ({
18
34
  onSubmit,
19
- sourceData,
35
+ sourceData = [],
20
36
  formFormationClass = "grid grid-cols-1 text-left gap-4",
21
37
  formParentClass = "w-96",
22
- }: FormRendererProps) => {
23
- const formRef = useRef<FormElement>(null);
38
+ }) => {
39
+ const formRef = useRef<HTMLFormElement>(null);
24
40
  const [requirementError, setRequirementError] = useState<string[]>([]);
25
-
26
41
  const { context, updateContext } = useFormContext();
27
42
 
28
- const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
43
+ // Handle form submission
44
+ const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
29
45
  event.preventDefault();
30
- const requirementErrorItems: string[] = [];
31
46
 
32
- sourceData?.forEach((item: FormItem) => {
33
- if (item.required && item.name) {
47
+ const requirementErrorItems = sourceData
48
+ .filter((item) => item.required && item.name)
49
+ .reduce((errors: string[], item) => {
34
50
  const field = formRef.current?.querySelector(
35
51
  `[name="${item.name}"]`
36
52
  ) as HTMLInputElement | null;
37
53
 
38
- if (!field || !field.value.trim()) {
39
- requirementErrorItems.push(item.name);
54
+ if (!validateField(field, item)) {
55
+ errors.push(item.name!);
40
56
  }
41
- }
42
- });
57
+ return errors;
58
+ }, []);
43
59
 
44
60
  setRequirementError(requirementErrorItems);
45
61
 
46
- if (requirementErrorItems.length > 0) return;
62
+ if (requirementErrorItems.length === 0 && onSubmit && formRef.current) {
63
+ onSubmit(new FormData(formRef.current));
64
+ }
65
+ };
47
66
 
48
- const formData = new FormData(formRef.current as HTMLFormElement);
49
- if (onSubmit) onSubmit(formData);
67
+ // Render form component based on the type
68
+ const renderFormComponent = (item: FormItem, index: number) => {
69
+ if (item.component === "button") {
70
+ return (
71
+ <div key={index} className="w-full mt-1">
72
+ <button
73
+ type={item.button_type}
74
+ className="w-full bg-black text-white py-2 rounded-xl hover:bg-gray-800"
75
+ >
76
+ {item.value}
77
+ </button>
78
+ </div>
79
+ );
80
+ }
81
+
82
+ const Component = item.component && COMPONENT_MAP[item.component];
83
+ if (!Component) return null;
84
+
85
+ return (
86
+ <Component
87
+ key={index}
88
+ item={item}
89
+ requirementError={requirementError}
90
+ setRequirementError={setRequirementError}
91
+ formRef={formRef}
92
+ onChangeEvent={item.onChangeEvent}
93
+ context={context}
94
+ updateContext={updateContext}
95
+ />
96
+ );
50
97
  };
51
98
 
99
+ // If no source data is found, return a message
100
+ if (!sourceData.length) {
101
+ return <div>No Source Data Found</div>;
102
+ }
103
+
52
104
  return (
53
105
  <form ref={formRef} onSubmit={handleSubmit} className={formParentClass}>
54
- {sourceData && sourceData?.length > 0 ? (
55
- <div className={formFormationClass}>
56
- {sourceData.map((item: FormItem, index: number) => {
57
- switch (item.component) {
58
- case "input":
59
- return (
60
- <InputHandles
61
- key={index}
62
- item={item}
63
- requirementError={requirementError}
64
- setRequirementError={setRequirementError}
65
- onChangeEvent={item.onChangeEvent}
66
- formRef={formRef}
67
- context={context}
68
- updateContext={updateContext}
69
- />
70
- );
71
-
72
- case "select":
73
- return (
74
- <SelectHandles
75
- key={index}
76
- item={{
77
- name: item.name,
78
- label: item.label,
79
- options: item.options,
80
- value: item.value,
81
- required: Boolean(item.required),
82
- }}
83
- requirementError={requirementError}
84
- setRequirementError={setRequirementError}
85
- formRef={formRef}
86
- onChangeEvent={item.onChangeEvent}
87
- />
88
- );
89
-
90
- case "multi-select":
91
- return (
92
- <MultiHandles
93
- key={index}
94
- item={item}
95
- requirementError={requirementError}
96
- setRequirementError={setRequirementError}
97
- formRef={formRef}
98
- onChangeEvent={item.onChangeEvent}
99
- />
100
- );
101
-
102
- case "datepicker":
103
- return (
104
- <DatePickerHandles
105
- key={index}
106
- item={item}
107
- requirementError={requirementError}
108
- setRequirementError={setRequirementError}
109
- formRef={formRef}
110
- onChangeEvent={item.onChangeEvent}
111
- />
112
- );
113
-
114
- case "checkbox":
115
- return (
116
- <CheckboxHandles
117
- key={index}
118
- item={item}
119
- requirementError={requirementError}
120
- setRequirementError={setRequirementError}
121
- formRef={formRef}
122
- onChangeEvent={item.onChangeEvent}
123
- sourceData={sourceData}
124
- context={context}
125
- updateContext={updateContext}
126
- />
127
- );
128
-
129
- case "button":
130
- return (
131
- <div key={index} className="w-full mt-1">
132
- <button
133
- type={item.button_type}
134
- 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"
135
- >
136
- {item.value}
137
- </button>
138
- </div>
139
- );
140
-
141
- default:
142
- return null;
143
- }
144
- })}
145
- </div>
146
- ) : (
147
- <div>No Source Data Found</div>
148
- )}
106
+ <div className={formFormationClass}>
107
+ {sourceData.map(renderFormComponent)}
108
+ </div>
149
109
  </form>
150
110
  );
151
111
  };
@@ -1,3 +1,7 @@
1
+ export type Option = {
2
+ value: string;
3
+ label: string;
4
+ };
1
5
  export interface FormElement extends HTMLFormElement {
2
6
  [key: string]: any;
3
7
  }
@@ -5,7 +9,13 @@ export interface FormElement extends HTMLFormElement {
5
9
  export type FormItem = {
6
10
  id?: string;
7
11
  name?: string;
8
- component?: string;
12
+ component?:
13
+ | "input"
14
+ | "select"
15
+ | "multi-select"
16
+ | "datepicker"
17
+ | "checkbox"
18
+ | "button";
9
19
  type?: string;
10
20
  required?: boolean | string;
11
21
  placeholder?: string;
@@ -26,39 +36,15 @@ export type FormItem = {
26
36
  };
27
37
  };
28
38
 
29
- interface DependencyConfig {
30
- source: string;
31
- parent?: string;
32
- dataStructure: any;
33
- }
34
-
35
39
  export type FormRendererProps = {
36
40
  onSubmit?: (formData: FormData) => void;
37
41
  sourceData?: FormItem[] | undefined;
38
42
  formFormationClass?: string;
39
43
  formParentClass?: string;
40
- dependencyConfig?: Record<string, DependencyConfig>;
41
- };
42
-
43
- export type SelectHandlesProps = {
44
- item?: FormItem;
45
- requirementError: string[];
46
- setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
47
- formRef?: React.RefObject<HTMLFormElement | null>;
48
- dependencyMap?: Record<
49
- string,
50
- {
51
- source: string;
52
- parent?: string;
53
- dataStructure: any;
54
- }
55
- >;
56
44
  };
57
45
 
58
- export type Option = {
59
- value: string;
60
- label: string;
61
- };
46
+ // Handler Props Starts here
47
+ export type FieldValue = string | boolean | number | null;
62
48
 
63
49
  export type CheckboxHandlesProps = {
64
50
  item?: FormItem;
@@ -77,10 +63,59 @@ export type CheckboxHandlesProps = {
77
63
  ) => void;
78
64
  };
79
65
 
80
- export type FieldValue = string | boolean | number | null;
81
-
82
66
  export interface FormContext {
83
67
  [componentName: string]: {
84
68
  [fieldName: string]: FieldValue;
85
69
  };
86
70
  }
71
+
72
+ export type InputHandlesProps = {
73
+ item?: FormItem;
74
+ requirementError: string[];
75
+ setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
76
+ onChangeEvent?: (event: React.ChangeEvent<HTMLInputElement>) => void;
77
+ formRef: React.RefObject<HTMLFormElement | null>;
78
+ context: FormContext;
79
+ updateContext: (
80
+ componentName: string,
81
+ fieldName: string,
82
+ value: FieldValue
83
+ ) => void;
84
+ };
85
+
86
+ export type DatePickerHandlesProps = {
87
+ item?: FormItem;
88
+ requirementError: string[];
89
+ setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
90
+ formRef?: React.RefObject<HTMLFormElement | null>;
91
+ onChangeEvent?: (event: any) => void;
92
+ };
93
+
94
+ export type SelectHandlesProps = {
95
+ item?: FormItem;
96
+ requirementError: string[];
97
+ setRequirementError: React.Dispatch<React.SetStateAction<string[]>>;
98
+ formRef: React.RefObject<HTMLFormElement | null>;
99
+ onChangeEvent?: (event: any) => void;
100
+ context: FormContext;
101
+ updateContext: (
102
+ componentName: string,
103
+ fieldName: string,
104
+ value: FieldValue
105
+ ) => void;
106
+ };
107
+
108
+ export type MultiSelectHandlesProps = {
109
+ item?: FormItem;
110
+ requirementError: string[];
111
+ setRequirementError?: React.Dispatch<React.SetStateAction<string[]>>;
112
+ formRef?: React.RefObject<HTMLFormElement | null>;
113
+ onChangeEvent?: (event: any) => void;
114
+ context: FormContext;
115
+ updateContext: (
116
+ componentName: string,
117
+ fieldName: string,
118
+ value: FieldValue
119
+ ) => void;
120
+ };
121
+ // Handler Props Ends here
@@ -17,6 +17,7 @@ import type { MultiSelectHandle, MultiSelectProps } from "./types";
17
17
  import {
18
18
  useMultiSelectState,
19
19
  useClickOutside,
20
+ applyScrollbarStyles,
20
21
  } from "@grampro/headless-helpers";
21
22
  import Icon from "../icon/Icon";
22
23
  import { check, search, upDown, x } from "../icon/iconPaths";
@@ -34,8 +35,11 @@ const MultiSelect = forwardRef<MultiSelectHandle, MultiSelectProps>(
34
35
  selectedItems = [],
35
36
  name,
36
37
  error,
38
+ disabled = false,
37
39
  } = props;
38
40
 
41
+ applyScrollbarStyles();
42
+
39
43
  const inputRef = useRef<HTMLInputElement>(null);
40
44
  const selectRef = useRef<HTMLDivElement>(null);
41
45
 
@@ -78,6 +82,12 @@ const MultiSelect = forwardRef<MultiSelectHandle, MultiSelectProps>(
78
82
  return display;
79
83
  }, [selected, workingDataSource, placeholder, truncate]);
80
84
 
85
+ const handleClear = () => {
86
+ if (disabled) return;
87
+ clearSelected();
88
+ if (onSelect) onSelect([]);
89
+ };
90
+
81
91
  useImperativeHandle(
82
92
  ref,
83
93
  () => ({
@@ -109,8 +119,11 @@ const MultiSelect = forwardRef<MultiSelectHandle, MultiSelectProps>(
109
119
  >
110
120
  <button
111
121
  onClick={togglePopover}
112
- className="flex-grow text-sm text-left font-medium"
122
+ className={`flex-grow text-sm text-left font-medium ${
123
+ disabled ? "opacity-50 cursor-not-allowed" : ""
124
+ }`}
113
125
  type="button"
126
+ disabled={disabled}
114
127
  >
115
128
  {getSelectedDisplay()}
116
129
  </button>
@@ -118,14 +131,19 @@ const MultiSelect = forwardRef<MultiSelectHandle, MultiSelectProps>(
118
131
  {selected.length > 0 && (
119
132
  <button
120
133
  className="flex items-center px-2"
121
- onClick={clearSelected}
134
+ onClick={handleClear}
122
135
  type="button"
123
136
  >
124
137
  <Icon elements={x} svgClass={iconClass["grey-common"]} />
125
138
  </button>
126
139
  )}
127
140
  <button onClick={togglePopover} type="button">
128
- <Icon elements={upDown} svgClass={iconClass["grey-common"]} />
141
+ <Icon
142
+ elements={upDown}
143
+ svgClass={`${iconClass["grey-common"]} ${
144
+ disabled ? "opacity-50" : ""
145
+ }`}
146
+ />
129
147
  </button>
130
148
  </div>
131
149
  </div>
@@ -138,7 +156,7 @@ const MultiSelect = forwardRef<MultiSelectHandle, MultiSelectProps>(
138
156
  readOnly
139
157
  />
140
158
 
141
- {showPopover && (
159
+ {showPopover && !disabled && (
142
160
  <div className={popUp["pop-up-style"]}>
143
161
  {showSearch && (
144
162
  <div className="flex p-2 gap-1 items-center sticky top-0 bg-white border-b dark:bg-black">
@@ -8,11 +8,12 @@ export type MultiSelectProps = {
8
8
  items?: ItemsProps[] | string;
9
9
  lazy?: boolean;
10
10
  showSearch?: boolean;
11
- onSelect?: (selectedItem: string[]) => void;
11
+ onSelect?: (selectedItem: string[]) => void | [];
12
12
  truncate?: boolean;
13
13
  selectedItems?: string[];
14
14
  name?: string;
15
15
  error?: string;
16
+ disabled?: boolean;
16
17
  };
17
18
 
18
19
  export type MultiSelectHandle = {
@@ -22,6 +22,7 @@ import {
22
22
  useSelectState,
23
23
  useSelectData,
24
24
  useClickOutside,
25
+ applyScrollbarStyles,
25
26
  } from "@grampro/headless-helpers";
26
27
 
27
28
  const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
@@ -36,8 +37,11 @@ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
36
37
  selectedItem: initialSelectedItem,
37
38
  error = undefined,
38
39
  onFiltering,
40
+ disabled = false,
39
41
  } = props;
40
42
 
43
+ applyScrollbarStyles();
44
+
41
45
  const {
42
46
  showPopover,
43
47
  setShowPopover,
@@ -90,6 +94,7 @@ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
90
94
  );
91
95
 
92
96
  const handleClear = () => {
97
+ if (disabled) return;
93
98
  clearSelected();
94
99
  if (onSelect) onSelect(undefined);
95
100
  };
@@ -110,14 +115,20 @@ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
110
115
  <button
111
116
  className={`${error ? primary["error-border"] : "border"} ${
112
117
  selectStyle["select-button"]
113
- }`}
118
+ } ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
114
119
  onClick={togglePopover}
115
120
  type="button"
121
+ disabled={disabled}
116
122
  >
117
123
  {selectedDisplay || placeholder}
118
- <Icon elements={upDown} svgClass={iconClass["grey-common"]} />
124
+ <Icon
125
+ elements={upDown}
126
+ svgClass={`${iconClass["grey-common"]} ${
127
+ disabled ? "opacity-50" : ""
128
+ }`}
129
+ />
119
130
  </button>
120
- {selectedDisplay && (
131
+ {selectedDisplay && !disabled && (
121
132
  <button
122
133
  className={selectStyle["selectedDisplay-Button"]}
123
134
  onClick={handleClear}
@@ -130,7 +141,7 @@ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
130
141
 
131
142
  <input type="hidden" name={name} value={selectedItem || ""} readOnly />
132
143
 
133
- {showPopover && (
144
+ {showPopover && !disabled && (
134
145
  <div className={popUp["pop-up-style"]}>
135
146
  {showSearch && (
136
147
  <div className={selectStyle["input-parent"]}>
@@ -141,7 +152,7 @@ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
141
152
  name="search"
142
153
  id="search"
143
154
  placeholder="Search a value"
144
- className="w-full outline-none dark:bg-black"
155
+ className="w-full outline-none"
145
156
  ref={inputRef}
146
157
  value={searchTerm}
147
158
  onChange={(e) => {
@@ -1,10 +1,9 @@
1
1
  export const selectStyle = {
2
2
  "select-button":
3
- "flex items-center px-4 py-2 w-full justify-between rounded-lg font-medium text-sm dark:bg-black dark:border-white dark:text-white",
3
+ "flex items-center px-4 py-2 w-full justify-between rounded-lg font-medium text-sm",
4
4
  "filter-button":
5
5
  "flex items-center w-full px-2 py-1 text-left hover:bg-blue-100 gap-2 rounded-lg mt-1 text-sm dark:hover:bg-blue-600",
6
- "input-parent":
7
- "flex p-2 gap-1 items-center sticky top-0 bg-white border-b dark:bg-black",
6
+ "input-parent": "flex p-2 gap-1 items-center sticky top-0 bg-white border-b",
8
7
  "selectedDisplay-Button":
9
8
  "absolute right-8 top-0 h-full flex items-center px-2 z-20",
10
9
  };
@@ -14,6 +14,7 @@ export type SelectProps = {
14
14
  onSelect?: (selectedItem: string | undefined) => void;
15
15
  selectedItem?: string;
16
16
  onFiltering?: (searchTerm: string) => void;
17
+ disabled?: boolean;
17
18
  };
18
19
 
19
20
  export type SelectHandle = {