gbs-add-block 0.0.30 → 0.0.32

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.25)
1
+ # GBS Building Blocks 2.0 (v0.0.31)
2
2
 
3
3
  Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
4
4
 
@@ -9,6 +9,8 @@ For detailed documentation on usage and props, Please visit: [Building Block Doc
9
9
  ## What's New 🎉 (Ver 0.0.23)
10
10
 
11
11
  - Updated Grid
12
+ - Updated Modal
13
+ - New Components (Material Input (Material Design Inspired Input), Form Renderer(Dynamic Form Rendering))
12
14
 
13
15
  ## Authors
14
16
 
package/index.js CHANGED
@@ -19,6 +19,7 @@ const COMPONENTS = [
19
19
  "Toast",
20
20
  "Uploader",
21
21
  "FormRenderer",
22
+ "materialInput",
22
23
  ];
23
24
 
24
25
  const FRAMEWORKS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbs-add-block",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "React Component Library",
5
5
  "files": [
6
6
  "index.js",
@@ -57,6 +57,7 @@ const InputHandles = ({
57
57
  ? "border-red-500"
58
58
  : "border-gray-300"
59
59
  }`}
60
+ defaultValue={item?.value ?? ""}
60
61
  />
61
62
  {item?.name && requirementError.includes(item.name) && (
62
63
  <p className="text-red-500 text-xs">{`${item?.name} is required`}</p>
@@ -43,6 +43,7 @@ export default function SelectHandles({
43
43
  <Select
44
44
  name={item?.name}
45
45
  items={item?.options}
46
+ selectedItem={item?.value ?? ""}
46
47
  onSelect={(value: string) => {
47
48
  item?.key && handleSelect(value, item.key);
48
49
  setRequirementError &&
@@ -10,7 +10,12 @@ import InputHandles from "./InputHandles";
10
10
  import SelectHandles from "./SelectHandles";
11
11
  import { FormItem, FormRendererProps } from "./types";
12
12
 
13
- const FormRenderer = ({ onSubmit, sourceData }: FormRendererProps) => {
13
+ const FormRenderer = ({
14
+ onSubmit,
15
+ sourceData,
16
+ formFormationClass = "grid grid-cols-1 text-left gap-4",
17
+ formParentClass = "w-96",
18
+ }: FormRendererProps) => {
14
19
  const formRef = useRef<HTMLFormElement>(null);
15
20
  const [requirementError, setRequirementError] = useState<string[]>([]);
16
21
 
@@ -40,9 +45,9 @@ const FormRenderer = ({ onSubmit, sourceData }: FormRendererProps) => {
40
45
  };
41
46
 
42
47
  return (
43
- <form ref={formRef} onSubmit={handleSubmit} className="w-96">
48
+ <form ref={formRef} onSubmit={handleSubmit} className={formParentClass}>
44
49
  {sourceData && sourceData?.length > 0 ? (
45
- <div className="flex flex-col items-start text-left gap-4">
50
+ <div className={formFormationClass}>
46
51
  {sourceData.map((item: FormItem, index: number) => {
47
52
  switch (item.component) {
48
53
  case "input":
@@ -68,7 +73,7 @@ const FormRenderer = ({ onSubmit, sourceData }: FormRendererProps) => {
68
73
 
69
74
  case "button":
70
75
  return (
71
- <div key={index} className="w-full mt-2">
76
+ <div key={index} className="w-full mt-1">
72
77
  <button
73
78
  type={item.button_type}
74
79
  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"
@@ -14,4 +14,6 @@ export type FormItem = {
14
14
  export type FormRendererProps = {
15
15
  onSubmit?: (formData: FormData) => void;
16
16
  sourceData?: FormItem[] | undefined;
17
+ formFormationClass?: string;
18
+ formParentClass?: string;
17
19
  };
@@ -0,0 +1,92 @@
1
+ import React, { useState, useRef } from "react";
2
+ import { MaterialInputProps } from "./types";
3
+
4
+ const MaterialInput = ({
5
+ label,
6
+ type = "text",
7
+ value,
8
+ onChange,
9
+ error,
10
+ helperText,
11
+ required = false,
12
+ disabled = false,
13
+ className = "",
14
+ }: MaterialInputProps) => {
15
+ const [isFocused, setIsFocused] = useState(false);
16
+ const inputRef = useRef<HTMLInputElement>(null);
17
+
18
+ const handleFocus = () => setIsFocused(true);
19
+ const handleBlur = () => {
20
+ if (!value) {
21
+ setIsFocused(false);
22
+ }
23
+ };
24
+
25
+ const isFloating = isFocused || value;
26
+
27
+ return (
28
+ <div className={`relative w-full ${className}`}>
29
+ <div className="relative">
30
+ <input
31
+ ref={inputRef}
32
+ type={type}
33
+ value={value}
34
+ onChange={(e) => onChange(e.target.value)}
35
+ onFocus={handleFocus}
36
+ onBlur={handleBlur}
37
+ disabled={disabled}
38
+ required={required}
39
+ className={`
40
+ peer w-full px-3 py-3
41
+ bg-transparent
42
+ border rounded-md
43
+ outline-none
44
+ transition-all duration-200 ease-in-out
45
+ placeholder-transparent
46
+ ${
47
+ error
48
+ ? "border-red-500 focus:border-red-500"
49
+ : "border-gray-300 focus:border-blue-500"
50
+ }
51
+ ${disabled ? "text-gray-400 cursor-not-allowed" : "text-gray-900"}
52
+ `}
53
+ />
54
+ <label
55
+ onClick={() => inputRef.current?.focus()}
56
+ className={`
57
+ absolute left-3
58
+ pointer-events-none
59
+ transition-all duration-200 ease-in-out
60
+ cursor-text
61
+ ${isFloating ? "-top-2 text-xs bg-white px-1" : "top-3 text-base"}
62
+ ${
63
+ error
64
+ ? "text-red-500"
65
+ : isFocused
66
+ ? "text-blue-500"
67
+ : "text-gray-500"
68
+ }
69
+ ${disabled ? "text-gray-400 cursor-not-allowed" : ""}
70
+ `}
71
+ >
72
+ {label}
73
+ {required && " *"}
74
+ </label>
75
+ </div>
76
+
77
+ {/* Helper text or error message */}
78
+ {(helperText || error) && (
79
+ <div
80
+ className={`
81
+ mt-1 text-xs
82
+ ${error ? "text-red-500" : "text-gray-500"}
83
+ `}
84
+ >
85
+ {error || helperText}
86
+ </div>
87
+ )}
88
+ </div>
89
+ );
90
+ };
91
+
92
+ export default MaterialInput;
@@ -0,0 +1,11 @@
1
+ export type MaterialInputProps = {
2
+ label: string;
3
+ type?: string;
4
+ value: string;
5
+ onChange: (value: string) => void;
6
+ error?: string;
7
+ helperText?: string;
8
+ required?: boolean;
9
+ disabled?: boolean;
10
+ className?: string;
11
+ };
@@ -5,20 +5,49 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React from "react";
8
+ import React, { useEffect } from "react";
9
9
  import { twMerge } from "tailwind-merge";
10
10
  import type { ModalProps } from "./types";
11
+ import Icon from "../icon/Icon";
12
+ import { x } from "../icon/iconPaths";
11
13
 
12
14
  export const Modal = ({
13
15
  showModal = false,
14
16
  modalTitle = "Modal Title",
15
17
  modalClass = "fixed z-10 overflow-y-auto inset-0 flex items-center justify-center bg-gray-500 bg-opacity-75 transition-opacity",
16
- modalContentClass = "bg-white m-10 md:w-[80vh] rounded-xl",
18
+ modalContentClass = "bg-white m-10 md:w-[80vh] rounded-xl relative",
17
19
  classModalContent = "",
18
- modalTitleClass = "p-4 text-lg leading-6 font-medium text-gray-900 flex justify-between",
20
+ modalTitleClass = "p-4 text-lg leading-6 font-medium text-gray-900 flex justify-between items-center",
19
21
  classModalTitle = "",
20
22
  children,
23
+ showCloseButton = false,
24
+ onClose,
25
+ dissmissible = false,
21
26
  }: ModalProps) => {
27
+ // Handle ESC key press to close modal
28
+ useEffect(() => {
29
+ const handleEscKey = (event: KeyboardEvent) => {
30
+ if (event.key === "Escape" && showModal && onClose) {
31
+ onClose();
32
+ }
33
+ };
34
+
35
+ if (showModal) {
36
+ document.addEventListener("keydown", handleEscKey);
37
+ }
38
+
39
+ return () => {
40
+ document.removeEventListener("keydown", handleEscKey);
41
+ };
42
+ }, [showModal, onClose]);
43
+
44
+ // Handle click outside modal to close
45
+ const handleOutsideClick = (e: React.MouseEvent) => {
46
+ if (onClose && e.target === e.currentTarget && dissmissible) {
47
+ onClose();
48
+ }
49
+ };
50
+
22
51
  return (
23
52
  <>
24
53
  {showModal && (
@@ -27,18 +56,33 @@ export const Modal = ({
27
56
  aria-labelledby="modal-title"
28
57
  role="dialog"
29
58
  aria-modal="true"
59
+ onClick={handleOutsideClick}
30
60
  >
31
61
  <div
32
62
  className={twMerge(modalContentClass, classModalContent)}
33
- onClick={(e: any) => {
63
+ onClick={(e: React.MouseEvent) => {
34
64
  e.stopPropagation();
35
65
  }}
36
66
  role="dialog"
37
67
  >
38
68
  <div className={twMerge(modalTitleClass, classModalTitle)}>
39
- {modalTitle}
69
+ <span>{modalTitle}</span>
70
+ {showCloseButton && onClose && (
71
+ <button
72
+ onClick={onClose}
73
+ className="p-2 hover:bg-gray-100 rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-gray-300"
74
+ aria-label="Close modal"
75
+ >
76
+ <Icon
77
+ elements={x}
78
+ svgClass={
79
+ "h-5 w-5 stroke-gray-500 fill-none dark:stroke-white"
80
+ }
81
+ />
82
+ </button>
83
+ )}
40
84
  </div>
41
- <hr />
85
+ <hr className="border-gray-200" />
42
86
  <div className="p-4">{children}</div>
43
87
  </div>
44
88
  </div>
@@ -8,4 +8,7 @@ export type ModalProps = {
8
8
  modalTitleClass?: string;
9
9
  classModalTitle?: string;
10
10
  children?: React.ReactNode;
11
+ showCloseButton?: boolean;
12
+ onClose?: () => void;
13
+ dissmissible?: boolean;
11
14
  };