@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ews-admin/global-design-system",
3
- "version": "1.1.15",
3
+ "version": "1.1.16",
4
4
  "description": "EWS Global Design System - Reusable components for EWS applications",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -1,7 +1,28 @@
1
- import React, { useState } from "react";
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
- {leftIcon && (
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
- leftIcon && "pl-10",
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";