@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/components/Input/Input.d.ts +8 -0
- package/dist/components/Input/Input.d.ts.map +1 -1
- package/dist/components/Modal/Modal.d.ts +5 -1
- package/dist/components/Modal/Modal.d.ts.map +1 -1
- package/dist/components/ProfileImageUpload/ProfileImageUpload.d.ts +47 -0
- package/dist/components/ProfileImageUpload/ProfileImageUpload.d.ts.map +1 -0
- package/dist/components/ProfileImageUpload/index.d.ts +3 -0
- package/dist/components/ProfileImageUpload/index.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +80 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +161 -26
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +161 -24
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Input/Input.tsx +28 -2
- package/src/components/Modal/Modal.tsx +20 -1
- package/src/components/ProfileImageUpload/ProfileImageUpload.tsx +231 -0
- package/src/components/ProfileImageUpload/index.ts +2 -0
- package/src/index.ts +5 -0
- package/src/utils/index.ts +31 -0
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$
|
|
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$
|
|
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$
|
|
247
|
-
const Check = createLucideIcon("check", __iconNode$
|
|
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$
|
|
258
|
-
const ChevronDown = createLucideIcon("chevron-down", __iconNode$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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;
|