@ews-admin/global-design-system 1.1.10 → 1.1.12

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/dist/index.js CHANGED
@@ -65,6 +65,25 @@ function debounce(func, wait) {
65
65
  function generateId(prefix = "ews") {
66
66
  return `${prefix}-${Math.random().toString(36).substr(2, 9)}`;
67
67
  }
68
+ /**
69
+ * Utility function to format numeric input by removing non-digit characters
70
+ * @param value - String value to format
71
+ * @returns String with only numeric characters
72
+ */
73
+ const formatNumeric = (value) => {
74
+ return value.replace(/\D/g, "");
75
+ };
76
+ /**
77
+ * Utility function to validate phone numbers
78
+ * Validates phone numbers with 1-15 digits, starting with a non-zero digit
79
+ * @param value - Phone number string to validate
80
+ * @returns Boolean indicating if the phone number is valid
81
+ */
82
+ function isValidPhoneNumber(value) {
83
+ const trimmedValue = value.trim();
84
+ const phoneRegex = /^[0-9]\d{1,14}$/;
85
+ return phoneRegex.test(trimmedValue);
86
+ }
68
87
 
69
88
  const Button = React.forwardRef(({ className, variant = "primary", size = "md", loading = false, fullWidth = false, leftIcon, rightIcon, children, disabled, ...props }, ref) => {
70
89
  const baseStyles = "inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none";
@@ -460,6 +479,20 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
460
479
  md: "h-5 w-5",
461
480
  lg: "h-6 w-6",
462
481
  };
482
+ const isCheckbox = type === "checkbox";
483
+ // For checkboxes, render with or without label based on label prop
484
+ if (isCheckbox) {
485
+ if (label) {
486
+ // Render checkbox with built-in label
487
+ return (jsxRuntime.jsx("div", { className: cn("space-y-1", fullWidth ? "w-full" : "w-auto"), children: jsxRuntime.jsxs("div", { className: "flex items-start space-x-3", children: [jsxRuntime.jsx("input", { id: inputId, type: actualType, className: cn("mt-0.5", // Slight top margin to align with first line of text
488
+ className), ref: ref, ...props }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsxs("label", { htmlFor: inputId, className: "block text-sm font-medium cursor-pointer text-ews-gray-700", children: [label, required && jsxRuntime.jsx("span", { className: "ml-1 text-ews-error", children: "*" })] }), (error || helperText) && (jsxRuntime.jsx("p", { className: cn("mt-1 text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] })] }) }));
489
+ }
490
+ else {
491
+ // Render just the checkbox for external label usage
492
+ return (jsxRuntime.jsx("input", { id: inputId, type: actualType, className: cn(className), ref: ref, ...props }));
493
+ }
494
+ }
495
+ // Default rendering for non-checkbox inputs
463
496
  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: [leftIcon && (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], leftIcon && "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 }))] }));
464
497
  });
465
498
  Input.displayName = "Input";
@@ -667,7 +700,7 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
667
700
  md: "w-4 h-4",
668
701
  lg: "w-5 h-5",
669
702
  };
670
- return (jsxRuntime.jsxs("div", { className: cn("w-full", containerClassName), ref: containerRef, children: [label && (jsxRuntime.jsxs("label", { htmlFor: selectId, className: cn("block text-sm font-medium mb-1", hasError ? "text-ews-error" : "text-ews-gray-700", disabled && "text-ews-gray-400"), children: [label, required && jsxRuntime.jsx("span", { className: "ml-1 text-ews-error", children: "*" })] })), jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("div", { ref: ref, role: "combobox", "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-labelledby": label ? selectId : undefined, tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown, onClick: handleToggle, className: cn(
703
+ return (jsxRuntime.jsxs("div", { className: cn("w-full", containerClassName), ref: containerRef, children: [label && (jsxRuntime.jsxs("label", { htmlFor: selectId, className: cn("block text-sm font-medium mb-1", "text-ews-gray-700", disabled && "text-ews-gray-400"), children: [label, required && jsxRuntime.jsx("span", { className: "ml-1 text-ews-error", children: "*" })] })), jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("div", { ref: ref, role: "combobox", "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-labelledby": label ? selectId : undefined, tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown, onClick: handleToggle, className: cn(
671
704
  // Base styles
672
705
  "ews-select-trigger w-full bg-white border rounded-md shadow-sm transition-colors cursor-pointer", "focus:outline-none focus:ring-2 focus:ring-offset-0", "disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-ews-gray-50",
673
706
  // Size
@@ -1111,6 +1144,7 @@ function useController(props) {
1111
1144
  exact: true,
1112
1145
  });
1113
1146
  const _props = React.useRef(props);
1147
+ const _previousNameRef = React.useRef(undefined);
1114
1148
  const _registerProps = React.useRef(control.register(name, {
1115
1149
  ...props.rules,
1116
1150
  value,
@@ -1176,6 +1210,10 @@ function useController(props) {
1176
1210
  }), [name, disabled, formState.disabled, onChange, onBlur, ref, value]);
1177
1211
  React.useEffect(() => {
1178
1212
  const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
1213
+ const previousName = _previousNameRef.current;
1214
+ if (previousName && previousName !== name && !isArrayField) {
1215
+ control.unregister(previousName);
1216
+ }
1179
1217
  control.register(name, {
1180
1218
  ..._props.current.rules,
1181
1219
  ...(isBoolean(_props.current.disabled)
@@ -1197,6 +1235,7 @@ function useController(props) {
1197
1235
  }
1198
1236
  }
1199
1237
  !isArrayField && control.register(name);
1238
+ _previousNameRef.current = name;
1200
1239
  return () => {
1201
1240
  (isArrayField
1202
1241
  ? _shouldUnregisterField && !control._state.action
@@ -1475,17 +1514,19 @@ function MultiSearchAutocomplete({ items, selectedItems, onSelectionChange, onSe
1475
1514
  };
1476
1515
  }, [isOpen]);
1477
1516
  // Default render functions
1478
- const defaultRenderSelectedItem = (entity) => (jsxRuntime.jsxs("span", { className: "inline-flex items-center px-3 py-1 text-sm font-medium rounded-full bg-ews-primary/10 text-ews-primary border border-ews-primary/20", children: [getPrimaryText(entity), jsxRuntime.jsx("button", { type: "button", onClick: () => handleRemoveItem(entity), className: "ml-2 text-ews-primary/60 hover:text-ews-primary", disabled: disabled, title: "Remove item", children: jsxRuntime.jsx(X, { className: "w-3 h-3" }) })] }));
1479
- const defaultRenderListItem = (entity, isSelected) => (jsxRuntime.jsxs("div", { className: "flex items-center space-x-3", children: [jsxRuntime.jsx("div", { className: cn("w-5 h-5 border-2 rounded flex items-center justify-center", isSelected ? "bg-ews-primary border-ews-primary" : "border-gray-300"), children: isSelected && jsxRuntime.jsx(Check, { className: "w-3 h-3 text-white" }) }), jsxRuntime.jsxs("div", { className: "flex flex-col", children: [jsxRuntime.jsx("span", { className: cn("font-medium", isSelected ? "text-ews-primary" : "text-gray-900"), children: getPrimaryText(entity) }), getSecondaryText && (jsxRuntime.jsx("span", { className: cn("text-sm", isSelected ? "text-ews-primary/70" : "text-gray-500"), children: getSecondaryText(entity) }))] })] }));
1517
+ const defaultRenderSelectedItem = (entity) => (jsxRuntime.jsxs("span", { className: "inline-flex items-center px-3 py-1 text-sm font-medium rounded-full border bg-ews-primary/10 text-ews-primary border-ews-primary/20", children: [getPrimaryText(entity), jsxRuntime.jsx("button", { type: "button", onClick: () => handleRemoveItem(entity), className: "ml-2 text-ews-primary/60 hover:text-ews-primary", disabled: disabled, title: "Remove item", children: jsxRuntime.jsx(X, { className: "w-3 h-3" }) })] }));
1518
+ const defaultRenderListItem = (entity, isSelected) => (jsxRuntime.jsxs("div", { className: "flex items-center space-x-3", children: [jsxRuntime.jsx("div", { className: cn("flex justify-center items-center w-5 h-5 rounded border-2", isSelected
1519
+ ? "bg-ews-primary border-ews-primary"
1520
+ : "border-ews-gray-300"), children: isSelected && jsxRuntime.jsx(Check, { className: "w-3 h-3 text-white" }) }), jsxRuntime.jsxs("div", { className: "flex flex-col", children: [jsxRuntime.jsx("span", { className: cn("font-medium", isSelected ? "text-ews-primary" : "text-gray-900"), children: getPrimaryText(entity) }), getSecondaryText && (jsxRuntime.jsx("span", { className: cn("text-sm", isSelected ? "text-ews-primary/70" : "text-gray-500"), children: getSecondaryText(entity) }))] })] }));
1480
1521
  return (jsxRuntime.jsxs("div", { className: cn("relative", className), ref: dropdownRef, children: [selectedItems.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 mb-3", children: selectedItems.map((item) => (jsxRuntime.jsx("div", { children: renderSelectedItem
1481
1522
  ? renderSelectedItem(item)
1482
- : defaultRenderSelectedItem(item) }, item.id))) })), jsxRuntime.jsx(Input, { ref: inputRef, type: "text", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, disabled: disabled, leftIcon: jsxRuntime.jsx(Search, { className: "w-4 h-4" }), className: "w-full" }), isOpen && !disabled && (jsxRuntime.jsx("div", { className: "absolute z-10 mt-1 w-full max-h-60 bg-white rounded-lg border border-gray-200 shadow-lg overflow-auto", children: loading || isSearching ? (jsxRuntime.jsxs("div", { className: "px-4 py-3 text-sm text-gray-500 flex items-center", children: [jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-ews-primary mr-2" }), isSearching ? "Searching..." : "Loading..."] })) : searchError ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-red-600", children: jsxRuntime.jsxs("div", { className: "flex items-center", children: [jsxRuntime.jsx(X, { className: "w-4 h-4 mr-2" }), "Error: ", searchError] }) })) : error ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-red-600", children: jsxRuntime.jsxs("div", { className: "flex items-center", children: [jsxRuntime.jsx(X, { className: "w-4 h-4 mr-2" }), error] }) })) : filteredItems.length === 0 ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-gray-500", children: searchTerm.length < minSearchLength
1523
+ : defaultRenderSelectedItem(item) }, item.id))) })), jsxRuntime.jsx(Input, { ref: inputRef, type: "text", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, disabled: disabled, leftIcon: jsxRuntime.jsx(Search, { className: "w-4 h-4" }), className: "w-full" }), isOpen && !disabled && (jsxRuntime.jsx("div", { className: "overflow-auto absolute z-10 mt-1 w-full max-h-60 bg-white rounded-lg border border-gray-200 shadow-lg", children: loading || isSearching ? (jsxRuntime.jsxs("div", { className: "flex items-center px-4 py-3 text-sm text-gray-500", children: [jsxRuntime.jsx("div", { className: "mr-2 w-4 h-4 rounded-full border-b-2 animate-spin border-ews-primary" }), isSearching ? "Searching..." : "Loading..."] })) : searchError ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-red-600", children: jsxRuntime.jsxs("div", { className: "flex items-center", children: [jsxRuntime.jsx(X, { className: "mr-2 w-4 h-4" }), "Error: ", searchError] }) })) : error ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-red-600", children: jsxRuntime.jsxs("div", { className: "flex items-center", children: [jsxRuntime.jsx(X, { className: "mr-2 w-4 h-4" }), error] }) })) : filteredItems.length === 0 ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-gray-500", children: searchTerm.length < minSearchLength
1483
1524
  ? `Type at least ${minSearchLength} characters to search`
1484
1525
  : "No items found" })) : (jsxRuntime.jsx("div", { className: "py-1", children: filteredItems.map((item) => {
1485
1526
  const isSelected = selectedItems.some((selected) => selected.id === item.id);
1486
- return (jsxRuntime.jsx("button", { type: "button", onClick: () => handleItemToggle(item), className: cn("w-full px-4 py-3 text-left flex items-center transition-colors", isSelected
1487
- ? "bg-ews-primary/10 text-ews-primary border-l-4 border-ews-primary"
1488
- : "hover:bg-ews-primary/5 text-gray-900"), children: renderListItem
1527
+ return (jsxRuntime.jsx("button", { type: "button", onClick: () => handleItemToggle(item), className: cn("flex items-center px-4 py-3 w-full text-left transition-colors", isSelected
1528
+ ? "border-l-4 bg-ews-primary/10 text-ews-primary border-ews-primary"
1529
+ : "text-gray-900 hover:bg-ews-primary/5"), children: renderListItem
1489
1530
  ? renderListItem(item, isSelected)
1490
1531
  : defaultRenderListItem(item, isSelected) }, item.id));
1491
1532
  }) })) }))] }));
@@ -1744,7 +1785,7 @@ const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesCh
1744
1785
  }, [specialties]);
1745
1786
  return (jsxRuntime.jsxs("div", { className: cn("space-y-3", className), children: [jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [jsxRuntime.jsx("div", { className: "flex justify-center items-center w-8 h-8 rounded-lg bg-secondary-100", children: jsxRuntime.jsx(Stethoscope, { className: "w-4 h-4 text-secondary-600" }) }), jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900", children: "Medical Specialties" })] }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Select Specialties" }) }), jsxRuntime.jsx(MultiSearchAutocomplete, { items: specialties, selectedItems: selectedSpecialties, onSelectionChange: handleSelectionChange, onSearch: fetchSpecialties, getEntityById: getEntityById, getPrimaryText: (specialty) => specialty.label, getSecondaryText: (specialty) => specialty.code, placeholder: placeholder, disabled: disabled, loading: isLoading, multiple: true, keepOpenOnSelect: true, className: "w-full", renderSelectedItem: (specialty) => (jsxRuntime.jsx("span", { className: "inline-flex items-center px-3 py-1 text-sm font-medium rounded-full bg-ews-primary/10 text-ews-primary border border-ews-primary/20", children: specialty.label })), renderListItem: (specialty, isSelected) => (jsxRuntime.jsxs("div", { className: "flex items-center space-x-3", children: [jsxRuntime.jsx("div", { className: cn("w-5 h-5 border-2 rounded flex items-center justify-center", isSelected
1746
1787
  ? "bg-ews-primary border-ews-primary"
1747
- : "border-gray-300"), children: isSelected && (jsxRuntime.jsx("svg", { className: "w-3 h-3 text-white", fill: "currentColor", viewBox: "0 0 20 20", children: jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) })) }), jsxRuntime.jsxs("div", { className: "flex flex-col", children: [jsxRuntime.jsx("span", { className: cn("font-medium", isSelected ? "text-ews-primary" : "text-gray-900"), children: specialty.label }), jsxRuntime.jsx("span", { className: cn("text-sm", isSelected ? "text-ews-primary/70" : "text-gray-500"), children: specialty.code })] })] })) }), showSelectedCount && selectedSpecialties.length > 0 && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-sm text-gray-600", children: [jsxRuntime.jsxs("span", { children: [selectedSpecialties.length, " specialty", selectedSpecialties.length !== 1 ? "ies" : "", " selected"] }), maxSelections && (jsxRuntime.jsxs("span", { className: "text-gray-400", children: [selectedSpecialties.length, "/", maxSelections] }))] }))] }));
1788
+ : "border-ews-gray-300"), children: isSelected && (jsxRuntime.jsx("svg", { className: "w-3 h-3 text-white", fill: "currentColor", viewBox: "0 0 20 20", children: jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) })) }), jsxRuntime.jsxs("div", { className: "flex flex-col", children: [jsxRuntime.jsx("span", { className: cn("font-medium", isSelected ? "text-ews-primary" : "text-gray-900"), children: specialty.label }), jsxRuntime.jsx("span", { className: cn("text-sm", isSelected ? "text-ews-primary/70" : "text-gray-500"), children: specialty.code })] })] })) }), showSelectedCount && selectedSpecialties.length > 0 && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-sm text-gray-600", children: [jsxRuntime.jsxs("span", { children: [selectedSpecialties.length, " specialty", selectedSpecialties.length !== 1 ? "ies" : "", " selected"] }), maxSelections && (jsxRuntime.jsxs("span", { className: "text-gray-400", children: [selectedSpecialties.length, "/", maxSelections] }))] }))] }));
1748
1789
  };
1749
1790
 
1750
1791
  exports.ArrowRight = ArrowRight;
@@ -1769,7 +1810,9 @@ exports.cn = cn;
1769
1810
  exports.debounce = debounce;
1770
1811
  exports.formatCurrency = formatCurrency;
1771
1812
  exports.formatDate = formatDate;
1813
+ exports.formatNumeric = formatNumeric;
1772
1814
  exports.generateId = generateId;
1815
+ exports.isValidPhoneNumber = isValidPhoneNumber;
1773
1816
  exports.useDebounce = useDebounce;
1774
1817
  exports.useDebouncedCallback = useDebouncedCallback;
1775
1818
  exports.useSelectField = useSelectField;