@ews-admin/global-design-system 1.1.15 → 1.1.16
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 +4 -0
- package/dist/components/Input/Input.d.ts +22 -0
- package/dist/components/Input/Input.d.ts.map +1 -1
- package/dist/components/Input/index.d.ts +1 -1
- package/dist/components/Input/index.d.ts.map +1 -1
- package/dist/index.css +2 -2
- package/dist/index.d.ts +22 -0
- package/dist/index.esm.css +2 -2
- package/dist/index.esm.js +23 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +22 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Input/Input.tsx +112 -3
- package/src/components/Input/index.ts +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ChevronDown } from "lucide-react";
|
|
2
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
3
|
import { Eye, EyeOff } from "../../icons";
|
|
3
4
|
import { cn } from "../../utils";
|
|
4
5
|
|
|
6
|
+
export interface CountryCodeOption {
|
|
7
|
+
code: string;
|
|
8
|
+
country: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface CountryCodeSelectProps {
|
|
12
|
+
/**
|
|
13
|
+
* Array of country code options
|
|
14
|
+
*/
|
|
15
|
+
options: CountryCodeOption[];
|
|
16
|
+
/**
|
|
17
|
+
* Currently selected country code
|
|
18
|
+
*/
|
|
19
|
+
value: string;
|
|
20
|
+
/**
|
|
21
|
+
* Handler for when country code changes
|
|
22
|
+
*/
|
|
23
|
+
onChange: (code: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
5
26
|
export interface InputProps
|
|
6
27
|
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {
|
|
7
28
|
/**
|
|
@@ -44,6 +65,10 @@ export interface InputProps
|
|
|
44
65
|
* Whether the input is required (shows red asterisk)
|
|
45
66
|
*/
|
|
46
67
|
required?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Country code dropdown configuration for phone inputs
|
|
70
|
+
*/
|
|
71
|
+
countryCodeSelect?: CountryCodeSelectProps;
|
|
47
72
|
}
|
|
48
73
|
|
|
49
74
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
@@ -60,6 +85,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
60
85
|
fullWidth = false,
|
|
61
86
|
showPasswordToggle = false,
|
|
62
87
|
required = false,
|
|
88
|
+
countryCodeSelect,
|
|
63
89
|
id,
|
|
64
90
|
type = "text",
|
|
65
91
|
...props
|
|
@@ -76,6 +102,25 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
76
102
|
const shouldShowPasswordToggle = showPasswordToggle && isPasswordInput;
|
|
77
103
|
const actualType = isPasswordInput && showPassword ? "text" : type;
|
|
78
104
|
|
|
105
|
+
// Country code dropdown state
|
|
106
|
+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
|
107
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
108
|
+
|
|
109
|
+
// Close dropdown when clicking outside
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
112
|
+
if (
|
|
113
|
+
dropdownRef.current &&
|
|
114
|
+
!dropdownRef.current.contains(event.target as Node)
|
|
115
|
+
) {
|
|
116
|
+
setIsDropdownOpen(false);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
121
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
122
|
+
}, []);
|
|
123
|
+
|
|
79
124
|
const baseStyles =
|
|
80
125
|
"block w-full rounded-md border transition-colors focus:outline-none focus:ring-2 focus:ring-offset-0 hover:border-ews-primary";
|
|
81
126
|
|
|
@@ -167,7 +212,69 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
167
212
|
</label>
|
|
168
213
|
)}
|
|
169
214
|
<div className="relative">
|
|
170
|
-
{
|
|
215
|
+
{countryCodeSelect && (
|
|
216
|
+
<div className="absolute inset-y-0 left-0 flex items-center pl-1 z-10" ref={dropdownRef}>
|
|
217
|
+
<div className="relative">
|
|
218
|
+
<button
|
|
219
|
+
type="button"
|
|
220
|
+
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
|
|
221
|
+
className={cn(
|
|
222
|
+
"flex items-center gap-1 px-2 py-1 rounded text-ews-gray-700",
|
|
223
|
+
"hover:bg-ews-gray-50 transition-colors cursor-pointer",
|
|
224
|
+
"focus:outline-none focus:ring-2 focus:ring-ews-primary focus:ring-offset-0",
|
|
225
|
+
"border-0 bg-transparent text-base"
|
|
226
|
+
)}
|
|
227
|
+
>
|
|
228
|
+
<span className="font-medium">{countryCodeSelect.value}</span>
|
|
229
|
+
<ChevronDown
|
|
230
|
+
className={cn(
|
|
231
|
+
"w-4 h-4 text-ews-gray-400 transition-transform",
|
|
232
|
+
isDropdownOpen && "rotate-180"
|
|
233
|
+
)}
|
|
234
|
+
/>
|
|
235
|
+
</button>
|
|
236
|
+
|
|
237
|
+
{isDropdownOpen && (
|
|
238
|
+
<div
|
|
239
|
+
className={cn(
|
|
240
|
+
"absolute top-full left-0 mt-1 bg-white rounded-md border shadow-lg",
|
|
241
|
+
"border-ews-gray-300 min-w-[120px] z-50"
|
|
242
|
+
)}
|
|
243
|
+
style={{ maxHeight: "200px", overflowY: "auto" }}
|
|
244
|
+
>
|
|
245
|
+
{countryCodeSelect.options.map((item) => {
|
|
246
|
+
const isSelected = item.code === countryCodeSelect.value;
|
|
247
|
+
return (
|
|
248
|
+
<div
|
|
249
|
+
key={item.code}
|
|
250
|
+
onClick={() => {
|
|
251
|
+
countryCodeSelect.onChange(item.code);
|
|
252
|
+
setIsDropdownOpen(false);
|
|
253
|
+
}}
|
|
254
|
+
className={cn(
|
|
255
|
+
"px-3 py-2 text-sm cursor-pointer transition-colors",
|
|
256
|
+
isSelected && "bg-ews-primary text-white",
|
|
257
|
+
!isSelected && "hover:bg-ews-gray-50"
|
|
258
|
+
)}
|
|
259
|
+
>
|
|
260
|
+
<span className="font-medium">{item.code}</span>
|
|
261
|
+
{item.country && (
|
|
262
|
+
<span className={cn(
|
|
263
|
+
"ml-2 text-xs",
|
|
264
|
+
isSelected ? "text-white/80" : "text-ews-gray-500"
|
|
265
|
+
)}>
|
|
266
|
+
{item.country}
|
|
267
|
+
</span>
|
|
268
|
+
)}
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
})}
|
|
272
|
+
</div>
|
|
273
|
+
)}
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
)}
|
|
277
|
+
{leftIcon && !countryCodeSelect && (
|
|
171
278
|
<div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
|
|
172
279
|
<span className={cn("text-ews-gray-400", iconSizes[size])}>
|
|
173
280
|
{leftIcon}
|
|
@@ -181,7 +288,8 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
181
288
|
baseStyles,
|
|
182
289
|
variants[actualVariant],
|
|
183
290
|
sizes[size],
|
|
184
|
-
|
|
291
|
+
countryCodeSelect && "pl-24",
|
|
292
|
+
leftIcon && !countryCodeSelect && "pl-10",
|
|
185
293
|
(rightIcon || shouldShowPasswordToggle) && "pr-10",
|
|
186
294
|
className
|
|
187
295
|
)}
|
|
@@ -231,3 +339,4 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
231
339
|
Input.displayName = "Input";
|
|
232
340
|
|
|
233
341
|
export { Input };
|
|
342
|
+
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Input } from "./Input";
|
|
2
|
-
export type { InputProps } from "./Input";
|
|
2
|
+
export type { CountryCodeOption, CountryCodeSelectProps, InputProps } from "./Input";
|