gbs-add-block 1.2.4 → 1.2.6
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 +3 -3
- package/package.json +36 -30
- package/source/components/bargraph/index.tsx +4 -3
- package/source/components/bargraph/type.ts +1 -0
- package/source/components/button/index.tsx +41 -24
- package/source/components/card/index.tsx +30 -9
- package/source/components/checkbox/index.tsx +24 -15
- package/source/components/datagrid/context/GridContext.tsx +3 -3
- package/source/components/datepicker/index.tsx +2 -1
- package/source/components/input/index.tsx +141 -143
- package/source/components/modal/index.tsx +151 -139
- package/source/components/modal/types.ts +18 -16
- package/source/components/multiselect/PortalDropDown.tsx +2 -1
- package/source/components/multiselect/index.tsx +3 -2
- package/source/components/select/PortalDropDown.tsx +21 -5
- package/source/components/select/index.tsx +8 -6
- package/source/components/select/types.ts +2 -0
- package/source/components/tabs/index.tsx +70 -51
- package/source/components/tabs/types.ts +15 -14
- package/source/components/textarea/index.tsx +122 -149
- package/source/globalStyle.ts +60 -34
- package/source/icon/iconPaths.ts +6 -0
- package/source/theme.ts +40 -0
|
@@ -1,150 +1,123 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from "react";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const [
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
setCharCount(
|
|
32
|
-
if (onChange) {
|
|
33
|
-
onChange(e);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
</svg>
|
|
124
|
-
{error}
|
|
125
|
-
</p>
|
|
126
|
-
)}
|
|
127
|
-
{!error && helperText && (
|
|
128
|
-
<p className="text-sm text-gray-500">{helperText}</p>
|
|
129
|
-
)}
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
{maxLength && (
|
|
133
|
-
<div className="ml-4 flex-shrink-0">
|
|
134
|
-
<span
|
|
135
|
-
className={`text-sm ${
|
|
136
|
-
charCount > maxLength * 0.9
|
|
137
|
-
? "text-amber-600"
|
|
138
|
-
: charCount === maxLength
|
|
139
|
-
? "text-red-600"
|
|
140
|
-
: "text-gray-400"
|
|
141
|
-
}`}
|
|
142
|
-
>
|
|
143
|
-
{charCount}/{maxLength}
|
|
144
|
-
</span>
|
|
145
|
-
</div>
|
|
146
|
-
)}
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
);
|
|
1
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
import type { TextAreaProps } from "./types";
|
|
4
|
+
|
|
5
|
+
export const TextArea = ({
|
|
6
|
+
label,
|
|
7
|
+
placeholder = "Enter your text here...",
|
|
8
|
+
value,
|
|
9
|
+
onChange,
|
|
10
|
+
error,
|
|
11
|
+
helperText,
|
|
12
|
+
rows = 4,
|
|
13
|
+
maxLength,
|
|
14
|
+
required = false,
|
|
15
|
+
disabled = false,
|
|
16
|
+
variant = "default",
|
|
17
|
+
className = "",
|
|
18
|
+
...props
|
|
19
|
+
}: TextAreaProps) => {
|
|
20
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
21
|
+
const [charCount, setCharCount] = useState(0);
|
|
22
|
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (typeof value === "string") {
|
|
26
|
+
setCharCount(value.length);
|
|
27
|
+
}
|
|
28
|
+
}, [value]);
|
|
29
|
+
|
|
30
|
+
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
31
|
+
setCharCount(e.target.value.length);
|
|
32
|
+
if (onChange) {
|
|
33
|
+
onChange(e);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const isFloating = variant === "minimal" && (isFocused || Boolean(value));
|
|
38
|
+
|
|
39
|
+
const variantClasses = {
|
|
40
|
+
default: {
|
|
41
|
+
textarea:
|
|
42
|
+
"border border-slate-300 bg-white text-slate-900 shadow-sm hover:border-slate-400 focus:border-sky-500 focus:ring-sky-500/20 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-100",
|
|
43
|
+
label: "mb-2 block text-sm font-medium text-slate-700 dark:text-slate-200",
|
|
44
|
+
},
|
|
45
|
+
minimal: {
|
|
46
|
+
textarea:
|
|
47
|
+
"border-0 border-b-2 border-slate-200 bg-transparent px-0 shadow-none focus:border-sky-500 dark:border-slate-700 dark:text-slate-100",
|
|
48
|
+
label: twMerge(
|
|
49
|
+
"absolute left-0 pointer-events-none transition-all duration-200",
|
|
50
|
+
isFloating ? "-top-5 text-xs text-sky-600" : "top-3 text-sm text-slate-400"
|
|
51
|
+
),
|
|
52
|
+
},
|
|
53
|
+
glass: {
|
|
54
|
+
textarea:
|
|
55
|
+
"border border-white/40 bg-white/70 text-slate-900 shadow-sm backdrop-blur hover:border-white/70 focus:border-sky-500 focus:ring-sky-500/20 dark:border-white/10 dark:bg-slate-950/70 dark:text-slate-100",
|
|
56
|
+
label: "mb-2 block text-sm font-medium text-slate-700 dark:text-slate-200",
|
|
57
|
+
},
|
|
58
|
+
}[variant];
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div className={twMerge("relative w-full", className)}>
|
|
62
|
+
{label && variant !== "minimal" && (
|
|
63
|
+
<label className={variantClasses.label}>
|
|
64
|
+
{label}
|
|
65
|
+
{required && <span className="ml-1 text-rose-500">*</span>}
|
|
66
|
+
</label>
|
|
67
|
+
)}
|
|
68
|
+
|
|
69
|
+
<div className="relative">
|
|
70
|
+
<textarea
|
|
71
|
+
ref={textareaRef}
|
|
72
|
+
value={value}
|
|
73
|
+
onChange={handleChange}
|
|
74
|
+
onFocus={() => setIsFocused(true)}
|
|
75
|
+
onBlur={() => setIsFocused(false)}
|
|
76
|
+
placeholder={variant === "minimal" ? (isFocused ? placeholder : "") : placeholder}
|
|
77
|
+
rows={rows}
|
|
78
|
+
maxLength={maxLength}
|
|
79
|
+
required={required}
|
|
80
|
+
disabled={disabled}
|
|
81
|
+
className={twMerge(
|
|
82
|
+
"w-full resize-none rounded-lg px-3 py-3 text-sm outline-none transition-all duration-200 focus:ring-2 disabled:cursor-not-allowed disabled:bg-slate-50 disabled:opacity-60",
|
|
83
|
+
variantClasses.textarea,
|
|
84
|
+
error ? "border-rose-500 focus:border-rose-500 focus:ring-rose-500/20" : ""
|
|
85
|
+
)}
|
|
86
|
+
{...props}
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
{variant === "minimal" && label && (
|
|
90
|
+
<label
|
|
91
|
+
className={variantClasses.label}
|
|
92
|
+
onClick={() => textareaRef.current?.focus()}
|
|
93
|
+
>
|
|
94
|
+
{label}
|
|
95
|
+
{required && <span className="ml-1 text-rose-500">*</span>}
|
|
96
|
+
</label>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div className="mt-2 flex items-start justify-between gap-3">
|
|
101
|
+
<div className="min-w-0 flex-1">
|
|
102
|
+
{error ? (
|
|
103
|
+
<p className="text-xs font-medium text-rose-600">{error}</p>
|
|
104
|
+
) : helperText ? (
|
|
105
|
+
<p className="text-xs text-slate-500">{helperText}</p>
|
|
106
|
+
) : null}
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
{maxLength && (
|
|
110
|
+
<span
|
|
111
|
+
className={twMerge(
|
|
112
|
+
"shrink-0 text-xs text-slate-400",
|
|
113
|
+
charCount > maxLength * 0.9 ? "text-amber-600" : "",
|
|
114
|
+
charCount === maxLength ? "text-rose-600" : ""
|
|
115
|
+
)}
|
|
116
|
+
>
|
|
117
|
+
{charCount}/{maxLength}
|
|
118
|
+
</span>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
150
123
|
};
|
package/source/globalStyle.ts
CHANGED
|
@@ -1,35 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
1
|
+
import { getComponentPreset } from "./theme";
|
|
2
|
+
|
|
3
|
+
const preset = getComponentPreset();
|
|
4
|
+
|
|
5
|
+
export const primary = {
|
|
6
|
+
"error-border": "border border-rose-500 focus-within:border-rose-500",
|
|
7
|
+
"error-primary": `${preset.text.error} mt-1 pl-1`,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const popUp = {
|
|
11
|
+
"pop-up-style":
|
|
12
|
+
`${preset.surface.overlay} w-full absolute overflow-y-auto rounded-lg mt-1 scrollbar z-[90] h-44 text-sm text-slate-700 dark:text-slate-100 animate-fade-down animate-once animate-duration-200`,
|
|
13
|
+
"pop-up-style-calender":
|
|
14
|
+
`${preset.surface.overlay} w-full absolute overflow-y-auto rounded-lg mt-1 scrollbar z-[90] h-[370px] text-slate-700 dark:text-slate-100 animate-fade-down animate-once animate-duration-200`,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const iconClass = {
|
|
18
|
+
"grey-common": "h-4 w-4 stroke-slate-500 fill-none dark:stroke-slate-300",
|
|
19
|
+
"error-icon": "h-4 w-4 stroke-rose-500 fill-none dark:stroke-rose-400",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const inputStyles = {
|
|
23
|
+
default: `${preset.control} ${preset.radius} ${preset.focusRing} px-3 py-2 text-sm shadow-sm`,
|
|
24
|
+
error: "border-rose-500 focus-visible:ring-rose-500",
|
|
25
|
+
otp: `${preset.control} ${preset.radius} ${preset.focusRing} m-1 h-10 w-9 text-center text-sm font-semibold`,
|
|
26
|
+
passwordToggle: "absolute inset-y-0 right-0 flex items-center pr-2",
|
|
27
|
+
otpContainer: "otp-container flex items-center gap-1",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const selectStyle = {
|
|
31
|
+
"select-button":
|
|
32
|
+
`${preset.control} ${preset.radius} ${preset.focusRing} flex min-h-10 w-full items-center justify-between gap-2 px-3 py-2 text-left text-sm font-medium shadow-sm`,
|
|
33
|
+
"filter-button":
|
|
34
|
+
"mt-1 flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-slate-700 transition-colors hover:bg-sky-50 hover:text-sky-700 dark:text-slate-100 dark:hover:bg-sky-950",
|
|
35
|
+
"input-parent":
|
|
36
|
+
"sticky top-0 z-50 flex w-full items-center gap-1 border-b border-slate-200 bg-white px-1 py-1 text-sm dark:border-slate-700 dark:bg-slate-950",
|
|
37
|
+
"selectedDisplay-Button":
|
|
38
|
+
"absolute right-8 top-1/2 z-20 flex -translate-y-1/2 items-center rounded-md p-1 transition-colors hover:bg-slate-100 dark:hover:bg-slate-800",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const buttonStyles = {
|
|
42
|
+
base: `${preset.radius} ${preset.focusRing} ${preset.disabled} inline-flex items-center justify-center gap-2 font-medium transition-colors`,
|
|
43
|
+
sizes: {
|
|
44
|
+
sm: "h-8 px-3 text-xs",
|
|
45
|
+
md: "h-10 px-4 text-sm",
|
|
46
|
+
lg: "h-11 px-5 text-base",
|
|
47
|
+
},
|
|
48
|
+
variants: {
|
|
49
|
+
primary: "bg-slate-950 text-white hover:bg-slate-800 dark:bg-white dark:text-slate-950 dark:hover:bg-slate-200",
|
|
50
|
+
secondary: "bg-sky-600 text-white hover:bg-sky-700",
|
|
51
|
+
outline: "border border-slate-300 bg-white text-slate-900 hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-100 dark:hover:bg-slate-900",
|
|
52
|
+
ghost: "text-slate-700 hover:bg-slate-100 dark:text-slate-100 dark:hover:bg-slate-800",
|
|
53
|
+
danger: "bg-rose-600 text-white hover:bg-rose-700",
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const cardStyles = {
|
|
58
|
+
base: `${preset.surface.raised} rounded-lg p-4`,
|
|
59
|
+
interactive:
|
|
60
|
+
"transition-shadow hover:shadow-md hover:shadow-slate-900/10",
|
|
35
61
|
};
|
package/source/icon/iconPaths.ts
CHANGED
package/source/theme.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type ComponentPresetId = "gbs-basic";
|
|
2
|
+
|
|
3
|
+
export type ComponentSize = "sm" | "md" | "lg";
|
|
4
|
+
|
|
5
|
+
export type ComponentVariant =
|
|
6
|
+
| "primary"
|
|
7
|
+
| "secondary"
|
|
8
|
+
| "outline"
|
|
9
|
+
| "ghost"
|
|
10
|
+
| "danger";
|
|
11
|
+
|
|
12
|
+
export const defaultPresetId: ComponentPresetId = "gbs-basic";
|
|
13
|
+
|
|
14
|
+
export const componentPresets = {
|
|
15
|
+
"gbs-basic": {
|
|
16
|
+
id: "gbs-basic",
|
|
17
|
+
radius: "rounded-lg",
|
|
18
|
+
focusRing:
|
|
19
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500 focus-visible:ring-offset-2",
|
|
20
|
+
disabled: "disabled:cursor-not-allowed disabled:opacity-55",
|
|
21
|
+
text: {
|
|
22
|
+
label: "text-sm font-medium text-slate-700",
|
|
23
|
+
helper: "text-xs text-slate-500",
|
|
24
|
+
error: "text-xs font-medium text-rose-600",
|
|
25
|
+
},
|
|
26
|
+
surface: {
|
|
27
|
+
raised:
|
|
28
|
+
"border border-slate-200 bg-white shadow-sm shadow-slate-900/5 dark:border-slate-700 dark:bg-slate-950",
|
|
29
|
+
subtle:
|
|
30
|
+
"border border-slate-200 bg-slate-50 dark:border-slate-700 dark:bg-slate-900",
|
|
31
|
+
overlay:
|
|
32
|
+
"border border-slate-200 bg-white shadow-xl shadow-slate-900/10 dark:border-slate-700 dark:bg-slate-950",
|
|
33
|
+
},
|
|
34
|
+
control:
|
|
35
|
+
"border border-slate-300 bg-white text-slate-900 transition-colors placeholder:text-slate-400 hover:border-slate-400 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-100",
|
|
36
|
+
},
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
export const getComponentPreset = (presetId: ComponentPresetId = defaultPresetId) =>
|
|
40
|
+
componentPresets[presetId] || componentPresets[defaultPresetId];
|