@ews-admin/global-design-system 1.1.15 → 1.1.17
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 +3 -3
- package/dist/index.d.ts +22 -0
- package/dist/index.esm.css +3 -3
- package/dist/index.esm.js +82 -27
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +81 -26
- 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/dist/index.js
CHANGED
|
@@ -457,7 +457,7 @@ const UserIcon = ({ size = 24, color = "currentColor", className = "", ...props
|
|
|
457
457
|
return jsxRuntime.jsx(User, { size: size, color: color, className: className, ...props });
|
|
458
458
|
};
|
|
459
459
|
|
|
460
|
-
const Input = React.forwardRef(({ className, variant = "default", size = "md", label, helperText, error, leftIcon, rightIcon, fullWidth = false, showPasswordToggle = false, required = false, id, type = "text", ...props }, ref) => {
|
|
460
|
+
const Input = React.forwardRef(({ className, variant = "default", size = "md", label, helperText, error, leftIcon, rightIcon, fullWidth = false, showPasswordToggle = false, required = false, countryCodeSelect, id, type = "text", ...props }, ref) => {
|
|
461
461
|
const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
|
|
462
462
|
const hasError = Boolean(error);
|
|
463
463
|
const actualVariant = hasError ? "error" : variant;
|
|
@@ -466,6 +466,20 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
|
|
|
466
466
|
const isPasswordInput = type === "password";
|
|
467
467
|
const shouldShowPasswordToggle = showPasswordToggle && isPasswordInput;
|
|
468
468
|
const actualType = isPasswordInput && showPassword ? "text" : type;
|
|
469
|
+
// Country code dropdown state
|
|
470
|
+
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
|
|
471
|
+
const dropdownRef = React.useRef(null);
|
|
472
|
+
// Close dropdown when clicking outside
|
|
473
|
+
React.useEffect(() => {
|
|
474
|
+
const handleClickOutside = (event) => {
|
|
475
|
+
if (dropdownRef.current &&
|
|
476
|
+
!dropdownRef.current.contains(event.target)) {
|
|
477
|
+
setIsDropdownOpen(false);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
481
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
482
|
+
}, []);
|
|
469
483
|
const baseStyles = "block w-full rounded-md border transition-colors focus:outline-none focus:ring-2 focus:ring-offset-0 hover:border-ews-primary";
|
|
470
484
|
const variants = {
|
|
471
485
|
default: "border-ews-gray-300 focus:border-ews-primary focus:ring-ews-primary",
|
|
@@ -496,7 +510,13 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
|
|
|
496
510
|
}
|
|
497
511
|
}
|
|
498
512
|
// Default rendering for non-checkbox inputs
|
|
499
|
-
return (jsxRuntime.jsxs("div", { className: cn("space-y-1", fullWidth ? "w-full" : "w-auto"), children: [label && (jsxRuntime.jsxs("label", { htmlFor: inputId, className: "block text-sm font-medium text-ews-gray-700", children: [label, required && jsxRuntime.jsx("span", { className: "ml-1 text-ews-error", children: "*" })] })), jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
513
|
+
return (jsxRuntime.jsxs("div", { className: cn("space-y-1", fullWidth ? "w-full" : "w-auto"), children: [label && (jsxRuntime.jsxs("label", { htmlFor: inputId, className: "block text-sm font-medium text-ews-gray-700", children: [label, required && jsxRuntime.jsx("span", { className: "ml-1 text-ews-error", children: "*" })] })), jsxRuntime.jsxs("div", { className: "relative", children: [countryCodeSelect && (jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 flex items-center pl-1 z-10", ref: dropdownRef, children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => setIsDropdownOpen(!isDropdownOpen), className: cn("flex items-center gap-1 px-2 py-1 rounded text-ews-gray-700", "hover:bg-ews-gray-50 transition-colors cursor-pointer", "focus:outline-none focus:ring-2 focus:ring-ews-primary focus:ring-offset-0", "border-0 bg-transparent text-base"), children: [jsxRuntime.jsx("span", { className: "font-medium", children: countryCodeSelect.value }), jsxRuntime.jsx(ChevronDown, { className: cn("w-4 h-4 text-ews-gray-400 transition-transform", isDropdownOpen && "rotate-180") })] }), isDropdownOpen && (jsxRuntime.jsx("div", { className: cn("absolute top-full left-0 mt-1 bg-white rounded-md border shadow-lg", "border-ews-gray-300 min-w-[120px] z-50"), style: { maxHeight: "200px", overflowY: "auto" }, children: countryCodeSelect.options.map((item) => {
|
|
514
|
+
const isSelected = item.code === countryCodeSelect.value;
|
|
515
|
+
return (jsxRuntime.jsxs("div", { onClick: () => {
|
|
516
|
+
countryCodeSelect.onChange(item.code);
|
|
517
|
+
setIsDropdownOpen(false);
|
|
518
|
+
}, className: cn("px-3 py-2 text-sm cursor-pointer transition-colors", isSelected && "bg-ews-primary text-white", !isSelected && "hover:bg-ews-gray-50"), children: [jsxRuntime.jsx("span", { className: "font-medium", children: item.code }), item.country && (jsxRuntime.jsx("span", { className: cn("ml-2 text-xs", isSelected ? "text-white/80" : "text-ews-gray-500"), children: item.country }))] }, item.code));
|
|
519
|
+
}) }))] }) })), leftIcon && !countryCodeSelect && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none", children: jsxRuntime.jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: leftIcon }) })), jsxRuntime.jsx("input", { id: inputId, type: actualType, className: cn(baseStyles, variants[actualVariant], sizes[size], countryCodeSelect && "pl-24", leftIcon && !countryCodeSelect && "pl-10", (rightIcon || shouldShowPasswordToggle) && "pr-10", className), ref: ref, ...props }), rightIcon && !shouldShowPasswordToggle && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 right-0 items-center pr-3 pointer-events-none", children: jsxRuntime.jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: rightIcon }) })), shouldShowPasswordToggle && (jsxRuntime.jsx("button", { type: "button", className: "flex absolute inset-y-0 right-0 items-center pr-3", onClick: () => setShowPassword(!showPassword), tabIndex: -1, children: jsxRuntime.jsx("span", { className: cn("transition-colors text-ews-gray-400 hover:text-ews-gray-600", iconSizes[size]), children: showPassword ? jsxRuntime.jsx(EyeOff, { size: 16 }) : jsxRuntime.jsx(Eye, { size: 16 }) }) }))] }), (error || helperText) && (jsxRuntime.jsx("p", { className: cn("text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] }));
|
|
500
520
|
});
|
|
501
521
|
Input.displayName = "Input";
|
|
502
522
|
|
|
@@ -1083,33 +1103,68 @@ function useWatch(props) {
|
|
|
1083
1103
|
const _defaultValue = React.useRef(defaultValue);
|
|
1084
1104
|
const _compute = React.useRef(compute);
|
|
1085
1105
|
const _computeFormValues = React.useRef(undefined);
|
|
1106
|
+
const _prevControl = React.useRef(control);
|
|
1107
|
+
const _prevName = React.useRef(name);
|
|
1086
1108
|
_compute.current = compute;
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
else {
|
|
1106
|
-
updateValue(formValues);
|
|
1109
|
+
const [value, updateValue] = React.useState(() => {
|
|
1110
|
+
const defaultValue = control._getWatch(name, _defaultValue.current);
|
|
1111
|
+
return _compute.current ? _compute.current(defaultValue) : defaultValue;
|
|
1112
|
+
});
|
|
1113
|
+
const getCurrentOutput = React.useCallback((values) => {
|
|
1114
|
+
const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
|
|
1115
|
+
return _compute.current ? _compute.current(formValues) : formValues;
|
|
1116
|
+
}, [control._formValues, control._names, name]);
|
|
1117
|
+
const refreshValue = React.useCallback((values) => {
|
|
1118
|
+
if (!disabled) {
|
|
1119
|
+
const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
|
|
1120
|
+
if (_compute.current) {
|
|
1121
|
+
const computedFormValues = _compute.current(formValues);
|
|
1122
|
+
if (!deepEqual(computedFormValues, _computeFormValues.current)) {
|
|
1123
|
+
updateValue(computedFormValues);
|
|
1124
|
+
_computeFormValues.current = computedFormValues;
|
|
1107
1125
|
}
|
|
1108
1126
|
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1127
|
+
else {
|
|
1128
|
+
updateValue(formValues);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}, [control._formValues, control._names, disabled, name]);
|
|
1132
|
+
useIsomorphicLayoutEffect(() => {
|
|
1133
|
+
if (_prevControl.current !== control ||
|
|
1134
|
+
!deepEqual(_prevName.current, name)) {
|
|
1135
|
+
_prevControl.current = control;
|
|
1136
|
+
_prevName.current = name;
|
|
1137
|
+
refreshValue();
|
|
1138
|
+
}
|
|
1139
|
+
return control._subscribe({
|
|
1140
|
+
name,
|
|
1141
|
+
formState: {
|
|
1142
|
+
values: true,
|
|
1143
|
+
},
|
|
1144
|
+
exact,
|
|
1145
|
+
callback: (formState) => {
|
|
1146
|
+
refreshValue(formState.values);
|
|
1147
|
+
},
|
|
1148
|
+
});
|
|
1149
|
+
}, [control, exact, name, refreshValue]);
|
|
1111
1150
|
React.useEffect(() => control._removeUnmounted());
|
|
1112
|
-
|
|
1151
|
+
// If name or control changed for this render, synchronously reflect the
|
|
1152
|
+
// latest value so callers (like useController) see the correct value
|
|
1153
|
+
// immediately on the same render.
|
|
1154
|
+
// Optimize: Check control reference first before expensive deepEqual
|
|
1155
|
+
const controlChanged = _prevControl.current !== control;
|
|
1156
|
+
const prevName = _prevName.current;
|
|
1157
|
+
// Cache the computed output to avoid duplicate calls within the same render
|
|
1158
|
+
// We include shouldReturnImmediate in deps to ensure proper recomputation
|
|
1159
|
+
const computedOutput = React.useMemo(() => {
|
|
1160
|
+
if (disabled) {
|
|
1161
|
+
return null;
|
|
1162
|
+
}
|
|
1163
|
+
const nameChanged = !controlChanged && !deepEqual(prevName, name);
|
|
1164
|
+
const shouldReturnImmediate = controlChanged || nameChanged;
|
|
1165
|
+
return shouldReturnImmediate ? getCurrentOutput() : null;
|
|
1166
|
+
}, [disabled, controlChanged, name, prevName, getCurrentOutput]);
|
|
1167
|
+
return computedOutput !== null ? computedOutput : value;
|
|
1113
1168
|
}
|
|
1114
1169
|
|
|
1115
1170
|
/**
|
|
@@ -1237,7 +1292,7 @@ function useController(props) {
|
|
|
1237
1292
|
};
|
|
1238
1293
|
updateMounted(name, true);
|
|
1239
1294
|
if (_shouldUnregisterField) {
|
|
1240
|
-
const value = cloneObject(get(control._options.defaultValues, name));
|
|
1295
|
+
const value = cloneObject(get(control._options.defaultValues, name, _props.current.defaultValue));
|
|
1241
1296
|
set(control._defaultValues, name, value);
|
|
1242
1297
|
if (isUndefined(get(control._formValues, name))) {
|
|
1243
1298
|
set(control._formValues, name, value);
|