@ews-admin/global-design-system 1.14.0 → 1.17.1
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/ProfileImageUpload/ProfileImageUpload.d.ts +18 -5
- package/dist/components/ProfileImageUpload/ProfileImageUpload.d.ts.map +1 -1
- package/dist/components/ProfileImageUpload/index.d.ts +1 -1
- package/dist/components/ProfileImageUpload/index.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts +7 -0
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Tag/Tag.d.ts +8 -0
- package/dist/components/Tag/Tag.d.ts.map +1 -0
- package/dist/components/Tag/index.d.ts +3 -0
- package/dist/components/Tag/index.d.ts.map +1 -0
- package/dist/components/TagList/TagList.d.ts +14 -0
- package/dist/components/TagList/TagList.d.ts.map +1 -0
- package/dist/components/TagList/index.d.ts +3 -0
- package/dist/components/TagList/index.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +45 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +37 -24
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +39 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ProfileImageUpload/ProfileImageUpload.tsx +36 -9
- package/src/components/ProfileImageUpload/index.ts +4 -1
- package/src/components/Select/Select.tsx +48 -50
- package/src/components/Tag/Tag.tsx +33 -0
- package/src/components/Tag/index.ts +2 -0
- package/src/components/TagList/TagList.tsx +60 -0
- package/src/components/TagList/index.ts +2 -0
- package/src/index.ts +10 -1
package/dist/index.js
CHANGED
|
@@ -27428,7 +27428,7 @@ const __iconNode$2X = [
|
|
|
27428
27428
|
],
|
|
27429
27429
|
["circle", { cx: "7.5", cy: "7.5", r: ".5", fill: "currentColor", key: "kqv944" }]
|
|
27430
27430
|
];
|
|
27431
|
-
const Tag = createLucideIcon("tag", __iconNode$2X);
|
|
27431
|
+
const Tag$1 = createLucideIcon("tag", __iconNode$2X);
|
|
27432
27432
|
|
|
27433
27433
|
/**
|
|
27434
27434
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -32377,7 +32377,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
32377
32377
|
Tablet: Tablet,
|
|
32378
32378
|
TabletSmartphone: TabletSmartphone,
|
|
32379
32379
|
Tablets: Tablets,
|
|
32380
|
-
Tag: Tag,
|
|
32380
|
+
Tag: Tag$1,
|
|
32381
32381
|
Tags: Tags,
|
|
32382
32382
|
Tally1: Tally1,
|
|
32383
32383
|
Tally2: Tally2,
|
|
@@ -32673,7 +32673,7 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
|
|
|
32673
32673
|
});
|
|
32674
32674
|
Input.displayName = "Input";
|
|
32675
32675
|
|
|
32676
|
-
const Select = React.forwardRef(({ options = [], value, onChange, placeholder = "Select an option...", label, helperText, error, isError = false, size = "md", disabled = false, required = false, searchable = false, multiple: _multiple = false, selectClassName, containerClassName, dropdownClassName, maxHeight = 200, clearable = false, renderOption, renderValue, ...props }, ref) => {
|
|
32676
|
+
const Select = React.forwardRef(({ options = [], value, onChange, placeholder = "Select an option...", label, helperText, error, isError = false, size = "md", disabled = false, required = false, searchable = false, multiple: _multiple = false, selectClassName, containerClassName, dropdownClassName, maxHeight = 200, clearable = false, renderOption, renderValue, renderTrigger, ...props }, ref) => {
|
|
32677
32677
|
const generatedId = React.useId();
|
|
32678
32678
|
const selectId = `select-${generatedId}`;
|
|
32679
32679
|
const hasError = isError || !!error;
|
|
@@ -32706,15 +32706,6 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
|
|
|
32706
32706
|
const spaceAbove = containerRect.top;
|
|
32707
32707
|
// Add some buffer (20px) to prevent edge cases
|
|
32708
32708
|
const buffer = 20;
|
|
32709
|
-
console.log("Position calculation:", {
|
|
32710
|
-
spaceBelow,
|
|
32711
|
-
spaceAbove,
|
|
32712
|
-
dropdownHeight,
|
|
32713
|
-
viewportHeight,
|
|
32714
|
-
containerBottom: containerRect.bottom,
|
|
32715
|
-
shouldOpenTop: spaceBelow < dropdownHeight + buffer &&
|
|
32716
|
-
spaceAbove > dropdownHeight + buffer,
|
|
32717
|
-
});
|
|
32718
32709
|
// If there's not enough space below but enough space above, position on top
|
|
32719
32710
|
if (spaceBelow < dropdownHeight + buffer &&
|
|
32720
32711
|
spaceAbove > dropdownHeight + buffer) {
|
|
@@ -32734,13 +32725,6 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
|
|
|
32734
32725
|
const spaceBelow = viewportHeight - containerRect.bottom;
|
|
32735
32726
|
const spaceAbove = containerRect.top;
|
|
32736
32727
|
const actualDropdownHeight = dropdownRect.height;
|
|
32737
|
-
console.log("Position calculation with element:", {
|
|
32738
|
-
spaceBelow,
|
|
32739
|
-
spaceAbove,
|
|
32740
|
-
actualDropdownHeight,
|
|
32741
|
-
viewportHeight,
|
|
32742
|
-
containerBottom: containerRect.bottom,
|
|
32743
|
-
});
|
|
32744
32728
|
// If there's not enough space below but enough space above, position on top
|
|
32745
32729
|
if (spaceBelow < actualDropdownHeight &&
|
|
32746
32730
|
spaceAbove > actualDropdownHeight) {
|
|
@@ -32896,7 +32880,7 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
|
|
|
32896
32880
|
// Text color
|
|
32897
32881
|
"text-ews-gray-900",
|
|
32898
32882
|
// Padding for icons
|
|
32899
|
-
"pr-10", selectClassName), ...props, children: jsxRuntime.
|
|
32883
|
+
"pr-10", selectClassName), ...props, children: jsxRuntime.jsx("div", { className: "flex justify-between items-center", children: renderTrigger ? (renderTrigger()) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: selectedOption ? (renderValue ? (renderValue(selectedOption)) : (jsxRuntime.jsx("span", { className: "truncate", children: selectedOption.label }))) : (jsxRuntime.jsx("span", { className: "text-ews-gray-500", children: placeholder })) }), jsxRuntime.jsxs("div", { className: "flex items-center ml-2 space-x-1", children: [clearable && selectedOption && !disabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClear, className: "p-1 rounded hover:bg-ews-gray-100", children: jsxRuntime.jsx(X, { className: cn(iconSizeClasses[size], "text-ews-gray-400") }) })), jsxRuntime.jsx(ChevronDown, { className: cn(iconSizeClasses[size], hasError ? "text-ews-error" : "text-ews-gray-400", disabled && "text-ews-gray-300", isOpen && "rotate-180 transition-transform") })] })] })) }) }), isOpen && (jsxRuntime.jsxs("div", { ref: dropdownRef, role: "listbox", className: cn("absolute z-50 w-full bg-white rounded-md border shadow-lg border-ews-gray-300", "focus:outline-none", dropdownPosition === "top"
|
|
32900
32884
|
? "bottom-full mb-1"
|
|
32901
32885
|
: "top-full mt-1", dropdownClassName), style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsxRuntime.jsx("div", { className: "p-2 border-b border-ews-gray-200", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(Search, { className: "absolute left-3 top-1/2 w-4 h-4 transform -translate-y-1/2 text-ews-gray-400" }), jsxRuntime.jsx(Input, { ref: inputRef, type: "text", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), placeholder: "Search options...", leftIcon: jsxRuntime.jsx(Search, { className: "w-4 h-4 text-ews-gray-400" }) })] }) })), jsxRuntime.jsx("div", { className: "overflow-auto py-1", style: { maxHeight: `${maxHeight - (searchable ? 60 : 0)}px` }, children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-ews-gray-500", children: searchTerm ? "No options found" : "No options available" })) : (filteredOptions.map((option, index) => {
|
|
32902
32886
|
const isSelected = option.value === value;
|
|
@@ -33309,6 +33293,7 @@ const Modal = ({ isOpen, onClose, title, children, variant = "info", size = "md"
|
|
|
33309
33293
|
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 }))] }))] })] }));
|
|
33310
33294
|
};
|
|
33311
33295
|
|
|
33296
|
+
const ACCEPTED_MIME_TYPES = ["image/jpeg", "image/png", "image/webp"];
|
|
33312
33297
|
const SIZE_CLASSES = {
|
|
33313
33298
|
sm: "h-10 w-10",
|
|
33314
33299
|
md: "h-16 w-16",
|
|
@@ -33344,28 +33329,34 @@ function UploadProgressBar({ progress, isLoading, }) {
|
|
|
33344
33329
|
const indeterminate = isLoading && progress === 0;
|
|
33345
33330
|
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}%` } }) }));
|
|
33346
33331
|
}
|
|
33347
|
-
const ProfileImageUpload = ({ imageUrl, altText, readOnly = false, size = "lg", uploadProgress = 0, isLoading = false, showDeleteButton = true,
|
|
33332
|
+
const ProfileImageUpload = ({ imageUrl, altText, readOnly = false, size = "lg", uploadProgress = 0, isLoading = false, showDeleteButton = true, acceptedFormats = [...ACCEPTED_MIME_TYPES], maxFileSizeMB = 5, aspectRatioHint, onFileSelect, onFileSizeExceeded, onInvalidFormat, onDeleteConfirm, deleteConfirmTitle, deleteConfirmMessage, deleteConfirmLabel, cancelLabel, }) => {
|
|
33348
33333
|
const fileInputRef = React.useRef(null);
|
|
33349
33334
|
const [isHovered, setIsHovered] = React.useState(false);
|
|
33350
33335
|
const [showConfirm, setShowConfirm] = React.useState(false);
|
|
33336
|
+
const acceptAttr = acceptedFormats.join(",");
|
|
33351
33337
|
const handleEditClick = () => fileInputRef.current?.click();
|
|
33352
33338
|
const handleFileChange = (e) => {
|
|
33353
33339
|
const file = e.target.files?.[0];
|
|
33354
33340
|
if (!file)
|
|
33355
33341
|
return;
|
|
33342
|
+
if (acceptedFormats.indexOf(file.type) === -1) {
|
|
33343
|
+
onInvalidFormat?.();
|
|
33344
|
+
e.target.value = "";
|
|
33345
|
+
return;
|
|
33346
|
+
}
|
|
33356
33347
|
if (file.size > maxFileSizeMB * 1024 * 1024) {
|
|
33357
33348
|
onFileSizeExceeded?.();
|
|
33358
33349
|
e.target.value = "";
|
|
33359
33350
|
return;
|
|
33360
33351
|
}
|
|
33361
33352
|
onFileSelect(file);
|
|
33362
|
-
e.target.value = "";
|
|
33353
|
+
e.target.value = "";
|
|
33363
33354
|
};
|
|
33364
33355
|
const handleConfirmDelete = () => {
|
|
33365
33356
|
setShowConfirm(false);
|
|
33366
33357
|
onDeleteConfirm();
|
|
33367
33358
|
};
|
|
33368
|
-
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:
|
|
33359
|
+
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: acceptAttr, 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 }), aspectRatioHint && (jsxRuntime.jsxs("p", { className: "mt-1 text-xs text-gray-400", children: ["Ratio: ", aspectRatioHint] }))] }), 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 }) })] }));
|
|
33369
33360
|
};
|
|
33370
33361
|
|
|
33371
33362
|
const DropdownMultiSelect = ({ options, name, control, placeholder = "Select options", searchPlaceholder = "Search...", onChange, value: controlledValue, defaultValue, onValidate, disabled = false, error, label, className, }) => {
|
|
@@ -33717,6 +33708,28 @@ function RegionSelect({ country = exports.SupportedCountry.SENEGAL, value, onCha
|
|
|
33717
33708
|
return (jsxRuntime.jsx(Select, { options: options, value: value, onChange: (val) => onChange?.(val), label: label, placeholder: placeholder, error: error, isError: isError, disabled: disabled, required: required, searchable: true, containerClassName: containerClassName }));
|
|
33718
33709
|
}
|
|
33719
33710
|
|
|
33711
|
+
const Tag = ({ label, variant = "plain", className, }) => {
|
|
33712
|
+
const variantClass = variant === "primary"
|
|
33713
|
+
? "bg-ews-primary text-white"
|
|
33714
|
+
: variant === "secondary"
|
|
33715
|
+
? "bg-ews-secondary text-white"
|
|
33716
|
+
: "bg-gray-200 text-gray-800";
|
|
33717
|
+
return (jsxRuntime.jsx("span", { className: cn("inline-block rounded-md px-2.5 py-1 text-sm font-medium", variantClass, className), children: label }));
|
|
33718
|
+
};
|
|
33719
|
+
|
|
33720
|
+
const DEFAULT_MAX = 3;
|
|
33721
|
+
const TagList = ({ items, maxVisible = DEFAULT_MAX, showMoreLabel, showLessLabel, variant = "secondary", className, renderTag, }) => {
|
|
33722
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
33723
|
+
const hasMore = items.length > maxVisible;
|
|
33724
|
+
const visible = expanded ? items : items.slice(0, maxVisible);
|
|
33725
|
+
const handleToggle = (e) => {
|
|
33726
|
+
e.preventDefault();
|
|
33727
|
+
e.stopPropagation();
|
|
33728
|
+
setExpanded(prev => !prev);
|
|
33729
|
+
};
|
|
33730
|
+
return (jsxRuntime.jsxs("div", { className: cn("flex flex-wrap items-center gap-2", className), children: [visible.map((label, i) => renderTag ? (renderTag(label, i)) : (jsxRuntime.jsx(Tag, { label: label, variant: variant }, i))), hasMore && !expanded && (jsxRuntime.jsx("span", { className: "text-sm text-gray-400", children: "..." })), hasMore && (jsxRuntime.jsx("button", { onClick: handleToggle, className: "text-xs text-ews-primary hover:underline", children: expanded ? showLessLabel : showMoreLabel }))] }));
|
|
33731
|
+
};
|
|
33732
|
+
|
|
33720
33733
|
const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesChange, specialties: availableSpecialties, placeholder = "Search and select medical specialties...", className = "", disabled = false, maxSelections, showSelectedCount = true, title = "Medical Specialties", label = "Select Specialties", getSelectedCountText, }) => {
|
|
33721
33734
|
const [filteredSpecialties, setFilteredSpecialties] = React.useState([]);
|
|
33722
33735
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
@@ -37480,7 +37493,7 @@ exports.LucideTableRowsSplit = TableRowsSplit;
|
|
|
37480
37493
|
exports.LucideTablet = Tablet;
|
|
37481
37494
|
exports.LucideTabletSmartphone = TabletSmartphone;
|
|
37482
37495
|
exports.LucideTablets = Tablets;
|
|
37483
|
-
exports.LucideTag = Tag;
|
|
37496
|
+
exports.LucideTag = Tag$1;
|
|
37484
37497
|
exports.LucideTags = Tags;
|
|
37485
37498
|
exports.LucideTally1 = Tally1;
|
|
37486
37499
|
exports.LucideTally2 = Tally2;
|
|
@@ -38929,7 +38942,8 @@ exports.TabletSmartphoneIcon = TabletSmartphone;
|
|
|
38929
38942
|
exports.Tablets = Tablets;
|
|
38930
38943
|
exports.TabletsIcon = Tablets;
|
|
38931
38944
|
exports.Tag = Tag;
|
|
38932
|
-
exports.TagIcon = Tag;
|
|
38945
|
+
exports.TagIcon = Tag$1;
|
|
38946
|
+
exports.TagList = TagList;
|
|
38933
38947
|
exports.Tags = Tags;
|
|
38934
38948
|
exports.TagsIcon = Tags;
|
|
38935
38949
|
exports.Tally1 = Tally1;
|