@ews-admin/global-design-system 1.1.20 → 1.1.22

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
@@ -86,6 +86,36 @@ function isValidPhoneNumber(value) {
86
86
  const phoneRegex = /^(\+\d{1,17}|\d{1,17})$/;
87
87
  return phoneRegex.test(trimmedValue);
88
88
  }
89
+ /**
90
+ * Blood type enum matching backend BloodTypeEnum values
91
+ */
92
+ exports.BloodType = void 0;
93
+ (function (BloodType) {
94
+ BloodType["A_POSITIVE"] = "A+";
95
+ BloodType["A_NEGATIVE"] = "A-";
96
+ BloodType["B_POSITIVE"] = "B+";
97
+ BloodType["B_NEGATIVE"] = "B-";
98
+ BloodType["AB_POSITIVE"] = "AB+";
99
+ BloodType["AB_NEGATIVE"] = "AB-";
100
+ BloodType["O_POSITIVE"] = "O+";
101
+ BloodType["O_NEGATIVE"] = "O-";
102
+ BloodType["UNKNOWN"] = "UNKNOWN";
103
+ })(exports.BloodType || (exports.BloodType = {}));
104
+ /**
105
+ * Ordered list of all blood type values.
106
+ * Use this to build select/dropdown options.
107
+ */
108
+ const BLOOD_TYPES = [
109
+ exports.BloodType.A_POSITIVE,
110
+ exports.BloodType.A_NEGATIVE,
111
+ exports.BloodType.B_POSITIVE,
112
+ exports.BloodType.B_NEGATIVE,
113
+ exports.BloodType.AB_POSITIVE,
114
+ exports.BloodType.AB_NEGATIVE,
115
+ exports.BloodType.O_POSITIVE,
116
+ exports.BloodType.O_NEGATIVE,
117
+ exports.BloodType.UNKNOWN,
118
+ ];
89
119
 
90
120
  const Button = React.forwardRef(({ className, variant = "ews-primary", size = "md", loading = false, fullWidth = false, leftIcon, rightIcon, children, disabled, ...props }, ref) => {
91
121
  const baseStyles = "inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none disabled:opacity-50 disabled:pointer-events-none";
@@ -229,11 +259,11 @@ const createLucideIcon = (iconName, iconNode) => {
229
259
  */
230
260
 
231
261
 
232
- const __iconNode$c = [
262
+ const __iconNode$e = [
233
263
  ["path", { d: "M5 12h14", key: "1ays0h" }],
234
264
  ["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
235
265
  ];
236
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$c);
266
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$e);
237
267
 
238
268
  /**
239
269
  * @license lucide-react v0.544.0 - ISC
@@ -243,8 +273,8 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$c);
243
273
  */
244
274
 
245
275
 
246
- const __iconNode$b = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
247
- const Check = createLucideIcon("check", __iconNode$b);
276
+ const __iconNode$d = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
277
+ const Check = createLucideIcon("check", __iconNode$d);
248
278
 
249
279
  /**
250
280
  * @license lucide-react v0.544.0 - ISC
@@ -254,8 +284,8 @@ const Check = createLucideIcon("check", __iconNode$b);
254
284
  */
255
285
 
256
286
 
257
- const __iconNode$a = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
258
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$a);
287
+ const __iconNode$c = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
288
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$c);
259
289
 
260
290
  /**
261
291
  * @license lucide-react v0.544.0 - ISC
@@ -265,12 +295,12 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$a);
265
295
  */
266
296
 
267
297
 
268
- const __iconNode$9 = [
298
+ const __iconNode$b = [
269
299
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
270
300
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
271
301
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
272
302
  ];
273
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$9);
303
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$b);
274
304
 
275
305
  /**
276
306
  * @license lucide-react v0.544.0 - ISC
@@ -280,11 +310,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$9);
280
310
  */
281
311
 
282
312
 
283
- const __iconNode$8 = [
313
+ const __iconNode$a = [
284
314
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
285
315
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
286
316
  ];
287
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$8);
317
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$a);
288
318
 
289
319
  /**
290
320
  * @license lucide-react v0.544.0 - ISC
@@ -294,7 +324,7 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$8);
294
324
  */
295
325
 
296
326
 
297
- const __iconNode$7 = [
327
+ const __iconNode$9 = [
298
328
  [
299
329
  "path",
300
330
  {
@@ -312,7 +342,7 @@ const __iconNode$7 = [
312
342
  ],
313
343
  ["path", { d: "m2 2 20 20", key: "1ooewy" }]
314
344
  ];
315
- const EyeOff = createLucideIcon("eye-off", __iconNode$7);
345
+ const EyeOff = createLucideIcon("eye-off", __iconNode$9);
316
346
 
317
347
  /**
318
348
  * @license lucide-react v0.544.0 - ISC
@@ -322,7 +352,7 @@ const EyeOff = createLucideIcon("eye-off", __iconNode$7);
322
352
  */
323
353
 
324
354
 
325
- const __iconNode$6 = [
355
+ const __iconNode$8 = [
326
356
  [
327
357
  "path",
328
358
  {
@@ -332,7 +362,7 @@ const __iconNode$6 = [
332
362
  ],
333
363
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
334
364
  ];
335
- const Eye = createLucideIcon("eye", __iconNode$6);
365
+ const Eye = createLucideIcon("eye", __iconNode$8);
336
366
 
337
367
  /**
338
368
  * @license lucide-react v0.544.0 - ISC
@@ -342,7 +372,7 @@ const Eye = createLucideIcon("eye", __iconNode$6);
342
372
  */
343
373
 
344
374
 
345
- const __iconNode$5 = [
375
+ const __iconNode$7 = [
346
376
  [
347
377
  "path",
348
378
  {
@@ -351,7 +381,7 @@ const __iconNode$5 = [
351
381
  }
352
382
  ]
353
383
  ];
354
- const Heart = createLucideIcon("heart", __iconNode$5);
384
+ const Heart = createLucideIcon("heart", __iconNode$7);
355
385
 
356
386
  /**
357
387
  * @license lucide-react v0.544.0 - ISC
@@ -361,11 +391,31 @@ const Heart = createLucideIcon("heart", __iconNode$5);
361
391
  */
362
392
 
363
393
 
364
- const __iconNode$4 = [
394
+ const __iconNode$6 = [
395
+ [
396
+ "path",
397
+ {
398
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
399
+ key: "1a8usu"
400
+ }
401
+ ],
402
+ ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
403
+ ];
404
+ const Pencil = createLucideIcon("pencil", __iconNode$6);
405
+
406
+ /**
407
+ * @license lucide-react v0.544.0 - ISC
408
+ *
409
+ * This source code is licensed under the ISC license.
410
+ * See the LICENSE file in the root directory of this source tree.
411
+ */
412
+
413
+
414
+ const __iconNode$5 = [
365
415
  ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
366
416
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
367
417
  ];
368
- const Search = createLucideIcon("search", __iconNode$4);
418
+ const Search = createLucideIcon("search", __iconNode$5);
369
419
 
370
420
  /**
371
421
  * @license lucide-react v0.544.0 - ISC
@@ -375,14 +425,29 @@ const Search = createLucideIcon("search", __iconNode$4);
375
425
  */
376
426
 
377
427
 
378
- const __iconNode$3 = [
428
+ const __iconNode$4 = [
379
429
  ["path", { d: "M11 2v2", key: "1539x4" }],
380
430
  ["path", { d: "M5 2v2", key: "1yf1q8" }],
381
431
  ["path", { d: "M5 3H4a2 2 0 0 0-2 2v4a6 6 0 0 0 12 0V5a2 2 0 0 0-2-2h-1", key: "rb5t3r" }],
382
432
  ["path", { d: "M8 15a6 6 0 0 0 12 0v-3", key: "x18d4x" }],
383
433
  ["circle", { cx: "20", cy: "10", r: "2", key: "ts1r5v" }]
384
434
  ];
385
- const Stethoscope = createLucideIcon("stethoscope", __iconNode$3);
435
+ const Stethoscope = createLucideIcon("stethoscope", __iconNode$4);
436
+
437
+ /**
438
+ * @license lucide-react v0.544.0 - ISC
439
+ *
440
+ * This source code is licensed under the ISC license.
441
+ * See the LICENSE file in the root directory of this source tree.
442
+ */
443
+
444
+
445
+ const __iconNode$3 = [
446
+ ["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
447
+ ["path", { d: "M3 6h18", key: "d0wm0j" }],
448
+ ["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
449
+ ];
450
+ const Trash = createLucideIcon("trash", __iconNode$3);
386
451
 
387
452
  /**
388
453
  * @license lucide-react v0.544.0 - ISC
@@ -457,7 +522,7 @@ const UserIcon = ({ size = 24, color = "currentColor", className = "", ...props
457
522
  return jsxRuntime.jsx(User, { size: size, color: color, className: className, ...props });
458
523
  };
459
524
 
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) => {
525
+ const Input = React.forwardRef(({ className, variant = "default", size = "md", label, helperText, error, leftIcon, rightIcon, fullWidth = false, showPasswordToggle = false, required = false, countryCodeSelect, leftAddon, rightAddon, id, type = "text", ...props }, ref) => {
461
526
  const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
462
527
  const hasError = Boolean(error);
463
528
  const actualVariant = hasError ? "error" : variant;
@@ -516,7 +581,7 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
516
581
  countryCodeSelect.onChange(item.code);
517
582
  setIsDropdownOpen(false);
518
583
  }, 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 }))] }));
584
+ }) }))] }) })), leftIcon && !countryCodeSelect && !leftAddon && (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 }) })), leftAddon && !countryCodeSelect && !leftIcon && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pointer-events-none overflow-hidden rounded-l-md", children: jsxRuntime.jsx("span", { className: "flex items-center h-full px-3 text-sm font-medium whitespace-nowrap bg-ews-gray-50 border-r border-ews-gray-300 text-ews-gray-600", children: leftAddon }) })), jsxRuntime.jsx("input", { id: inputId, type: actualType, className: cn(baseStyles, variants[actualVariant], sizes[size], countryCodeSelect && "pl-24", leftIcon && !countryCodeSelect && !leftAddon && "pl-10", leftAddon && !countryCodeSelect && !leftIcon && "pl-16", (rightIcon || shouldShowPasswordToggle) && "pr-10", rightAddon && !rightIcon && !shouldShowPasswordToggle && "pr-16", className), ref: ref, ...props }), rightAddon && !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: "text-sm font-medium text-ews-gray-500", children: rightAddon }) })), 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 }))] }));
520
585
  });
521
586
  Input.displayName = "Input";
522
587
 
@@ -1640,7 +1705,7 @@ function MultiSearchAutocomplete({ items, selectedItems, onSelectionChange, onSe
1640
1705
  }) })) }))] }));
1641
1706
  }
1642
1707
 
1643
- const Modal = ({ isOpen, onClose, title, children, variant = "info", primaryAction, secondaryAction, onPrimaryAction, onSecondaryAction, isLoading = false, closeOnOverlayClick = true, className, contentClassName, error, }) => {
1708
+ const Modal = ({ isOpen, onClose, title, children, variant = "info", size = "md", primaryAction, secondaryAction, onPrimaryAction, onSecondaryAction, isLoading = false, closeOnOverlayClick = true, className, contentClassName, error, }) => {
1644
1709
  // Handle escape key press
1645
1710
  React.useEffect(() => {
1646
1711
  const handleEscape = (event) => {
@@ -1693,12 +1758,82 @@ const Modal = ({ isOpen, onClose, title, children, variant = "info", primaryActi
1693
1758
  }
1694
1759
  };
1695
1760
  const variantStyles = getVariantStyles();
1761
+ const getSizeClasses = () => {
1762
+ const sizeMap = {
1763
+ sm: "max-w-sm",
1764
+ md: "max-w-md",
1765
+ lg: "max-w-lg",
1766
+ xl: "max-w-xl",
1767
+ "2xl": "max-w-2xl",
1768
+ full: "max-w-full",
1769
+ };
1770
+ return sizeMap[size] || sizeMap.md;
1771
+ };
1696
1772
  const handleOverlayClick = (e) => {
1697
1773
  if (e.target === e.currentTarget && closeOnOverlayClick) {
1698
1774
  onClose();
1699
1775
  }
1700
1776
  };
1701
- return (jsxRuntime.jsxs("div", { className: "flex fixed inset-0 z-50 justify-center items-center", children: [jsxRuntime.jsx("div", { className: "absolute inset-0 backdrop-blur-sm bg-black/50", onClick: handleOverlayClick }), jsxRuntime.jsxs("div", { className: cn("relative mx-4 w-full max-w-md bg-white rounded-lg shadow-xl transition-all transform", "duration-200 animate-in fade-in-0 zoom-in-95", className), role: "dialog", "aria-modal": "true", "aria-labelledby": "modal-title", children: [jsxRuntime.jsxs("div", { className: cn("flex items-center justify-between p-6 border-b", variantStyles.borderColor), children: [jsxRuntime.jsxs("div", { className: "flex items-center space-x-3", children: [jsxRuntime.jsx("div", { className: cn("p-2 rounded-full", variantStyles.iconBg), children: variantStyles.icon }), jsxRuntime.jsx("h2", { id: "modal-title", className: cn("text-lg font-semibold", variantStyles.titleColor), children: title })] }), jsxRuntime.jsx("button", { onClick: onClose, className: "p-1 text-gray-400 transition-colors hover:text-gray-600", "aria-label": "Close modal", children: jsxRuntime.jsx(X, { className: "w-5 h-5" }) })] }), jsxRuntime.jsx("div", { className: cn("p-6", contentClassName), children: jsxRuntime.jsx("div", { className: "leading-relaxed text-gray-700", children: error && variant === "error" ? (jsxRuntime.jsxs("div", { className: "space-y-3", children: [jsxRuntime.jsx("p", { children: error.message }), error.fields && error.fields.length > 0 && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("p", { className: "font-semibold text-gray-900", children: "Erreurs de champ:" }), jsxRuntime.jsx("ul", { className: "mt-2 space-y-1", children: error.fields.map((field, index) => (jsxRuntime.jsxs("li", { className: "text-ews-error", children: ["\u2022 ", field.path, ": ", field.message] }, index))) })] }))] })) : (children) }) }), (primaryAction || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex justify-end items-center p-6 pt-0 space-x-3", children: [secondaryAction && (jsxRuntime.jsx(Button, { variant: "outline", onClick: onSecondaryAction || onClose, disabled: isLoading, children: secondaryAction })), primaryAction && (jsxRuntime.jsx(Button, { variant: variant === "error" ? "error" : "ews-primary", onClick: onPrimaryAction, loading: isLoading, children: primaryAction }))] }))] })] }));
1777
+ return (jsxRuntime.jsxs("div", { className: "flex fixed inset-0 z-50 justify-center items-center", children: [jsxRuntime.jsx("div", { className: "absolute inset-0 backdrop-blur-sm bg-black/50", onClick: handleOverlayClick }), jsxRuntime.jsxs("div", { className: cn("relative w-full bg-white rounded-lg shadow-xl transition-all transform", "duration-200 animate-in fade-in-0 zoom-in-95", getSizeClasses(), "mx-4", className), role: "dialog", "aria-modal": "true", "aria-labelledby": "modal-title", children: [jsxRuntime.jsxs("div", { className: cn("flex items-center justify-between p-6 border-b", variantStyles.borderColor), children: [jsxRuntime.jsxs("div", { className: "flex items-center space-x-3", children: [jsxRuntime.jsx("div", { className: cn("p-2 rounded-full", variantStyles.iconBg), children: variantStyles.icon }), jsxRuntime.jsx("h2", { id: "modal-title", className: cn("text-lg font-semibold", variantStyles.titleColor), children: title })] }), jsxRuntime.jsx("button", { onClick: onClose, className: "p-1 text-gray-400 transition-colors hover:text-gray-600", "aria-label": "Close modal", children: jsxRuntime.jsx(X, { className: "w-5 h-5" }) })] }), jsxRuntime.jsx("div", { className: cn("p-6", contentClassName), children: jsxRuntime.jsx("div", { className: "leading-relaxed text-gray-700", children: error && variant === "error" ? (jsxRuntime.jsxs("div", { className: "space-y-3", children: [jsxRuntime.jsx("p", { children: error.message }), error.fields && error.fields.length > 0 && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("p", { className: "font-semibold text-gray-900", children: "Erreurs de champ:" }), jsxRuntime.jsx("ul", { className: "mt-2 space-y-1", children: error.fields.map((field, index) => (jsxRuntime.jsxs("li", { className: "text-ews-error", children: ["\u2022 ", field.path, ": ", field.message] }, index))) })] }))] })) : (children) }) }), (primaryAction || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex justify-end items-center p-6 pt-0 space-x-3", children: [secondaryAction && (jsxRuntime.jsx(Button, { variant: "outline", onClick: onSecondaryAction || onClose, disabled: isLoading, children: secondaryAction })), primaryAction && (jsxRuntime.jsx(Button, { variant: variant === "error" ? "error" : "ews-primary", onClick: onPrimaryAction, loading: isLoading, children: primaryAction }))] }))] })] }));
1778
+ };
1779
+
1780
+ const SIZE_CLASSES = {
1781
+ sm: "h-10 w-10",
1782
+ md: "h-16 w-16",
1783
+ lg: "h-32 w-32",
1784
+ };
1785
+ const INDICATOR_CLASSES = {
1786
+ sm: "h-2 w-2",
1787
+ md: "h-4 w-4",
1788
+ lg: "h-8 w-8",
1789
+ };
1790
+ function UploadProgressBar({ progress, isLoading, }) {
1791
+ const [visible, setVisible] = React.useState(false);
1792
+ React.useEffect(() => {
1793
+ if (isLoading) {
1794
+ setVisible(true);
1795
+ return;
1796
+ }
1797
+ // isLoading just turned false
1798
+ if (progress >= 100) {
1799
+ setVisible(true);
1800
+ const t = setTimeout(() => setVisible(false), 1000);
1801
+ return () => clearTimeout(t);
1802
+ }
1803
+ // Legacy path (no isLoading prop): driven purely by progress
1804
+ if (progress > 0 && progress < 100) {
1805
+ setVisible(true);
1806
+ return;
1807
+ }
1808
+ setVisible(false);
1809
+ }, [progress, isLoading]);
1810
+ if (!visible)
1811
+ return null;
1812
+ const indeterminate = isLoading && progress === 0;
1813
+ return (jsxRuntime.jsx("div", { className: "mt-2 h-1.5 w-32 rounded-full bg-gray-200", children: jsxRuntime.jsx("div", { className: cn("h-full rounded-full bg-ews-primary transition-all duration-300", indeterminate && "animate-pulse"), style: { width: indeterminate ? "35%" : `${progress}%` } }) }));
1814
+ }
1815
+ const ProfileImageUpload = ({ imageUrl, altText, readOnly = false, size = "lg", uploadProgress = 0, isLoading = false, showDeleteButton = true, accept = "image/*", maxFileSizeMB = 3, onFileSelect, onFileSizeExceeded, onDeleteConfirm, deleteConfirmTitle, deleteConfirmMessage, deleteConfirmLabel, cancelLabel, }) => {
1816
+ const fileInputRef = React.useRef(null);
1817
+ const [isHovered, setIsHovered] = React.useState(false);
1818
+ const [showConfirm, setShowConfirm] = React.useState(false);
1819
+ const handleEditClick = () => fileInputRef.current?.click();
1820
+ const handleFileChange = (e) => {
1821
+ const file = e.target.files?.[0];
1822
+ if (!file)
1823
+ return;
1824
+ if (file.size > maxFileSizeMB * 1024 * 1024) {
1825
+ onFileSizeExceeded?.();
1826
+ e.target.value = "";
1827
+ return;
1828
+ }
1829
+ onFileSelect(file);
1830
+ e.target.value = ""; // allow re-selecting the same file
1831
+ };
1832
+ const handleConfirmDelete = () => {
1833
+ setShowConfirm(false);
1834
+ onDeleteConfirm();
1835
+ };
1836
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "inline-flex flex-col items-center", children: [jsxRuntime.jsxs("div", { className: "relative", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsxRuntime.jsx("img", { src: imageUrl, alt: altText, className: cn("rounded-full border-4 border-white object-cover", SIZE_CLASSES[size]) }), jsxRuntime.jsx("div", { className: cn("absolute bottom-0 right-0 rounded-full border-4 border-white bg-green-400", INDICATOR_CLASSES[size]) }), jsxRuntime.jsx("input", { type: "file", ref: fileInputRef, accept: accept, className: "hidden", onChange: handleFileChange }), isHovered && !readOnly && !isLoading && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { type: "button", onClick: handleEditClick, className: "absolute left-0 top-0 flex h-8 w-8 cursor-pointer items-center justify-center rounded-full bg-ews-primary transition-colors hover:bg-ews-secondary", "aria-label": "Edit profile image", children: jsxRuntime.jsx(Pencil, { className: "h-4 w-4 text-white" }) }), showDeleteButton && (jsxRuntime.jsx("button", { type: "button", onClick: () => setShowConfirm(true), className: "absolute left-0 top-10 flex h-8 w-8 cursor-pointer items-center justify-center rounded-full bg-red-600 transition-colors hover:bg-red-700", "aria-label": "Delete profile image", children: jsxRuntime.jsx(Trash, { className: "h-4 w-4 text-white" }) }))] }))] }), jsxRuntime.jsx(UploadProgressBar, { progress: uploadProgress, isLoading: isLoading })] }), jsxRuntime.jsx(Modal, { isOpen: showConfirm, onClose: () => setShowConfirm(false), title: deleteConfirmTitle, variant: "error", size: "sm", primaryAction: deleteConfirmLabel, secondaryAction: cancelLabel, onPrimaryAction: handleConfirmDelete, onSecondaryAction: () => setShowConfirm(false), children: jsxRuntime.jsx("p", { children: deleteConfirmMessage }) })] }));
1702
1837
  };
1703
1838
 
1704
1839
  const DropdownMultiSelect = ({ options, name, control, placeholder = "Select options", searchPlaceholder = "Search...", onChange, value: controlledValue, defaultValue, onValidate, disabled = false, error, label, className, }) => {
@@ -1988,6 +2123,7 @@ const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesCh
1988
2123
  };
1989
2124
 
1990
2125
  exports.ArrowRight = ArrowRight;
2126
+ exports.BLOOD_TYPES = BLOOD_TYPES;
1991
2127
  exports.Button = Button;
1992
2128
  exports.Check = Check;
1993
2129
  exports.DoctorIcon = DoctorIcon;
@@ -1998,6 +2134,7 @@ exports.Logo = Logo;
1998
2134
  exports.Modal = Modal;
1999
2135
  exports.MultiSearchAutocomplete = MultiSearchAutocomplete;
2000
2136
  exports.PatientIcon = PatientIcon;
2137
+ exports.ProfileImageUpload = ProfileImageUpload;
2001
2138
  exports.Search = Search;
2002
2139
  exports.SearchAutocomplete = SearchAutocomplete;
2003
2140
  exports.Select = Select;