@ews-admin/global-design-system 1.1.13 → 1.1.15
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/Button/Button.d.ts +1 -1
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/DropdownMultiSelect/DropdownMultiSelect.d.ts +22 -0
- package/dist/components/DropdownMultiSelect/DropdownMultiSelect.d.ts.map +1 -0
- package/dist/components/DropdownMultiSelect/index.d.ts +3 -0
- package/dist/components/DropdownMultiSelect/index.d.ts.map +1 -0
- package/dist/components/Logo/Logo.d.ts +3 -27
- package/dist/components/Logo/Logo.d.ts.map +1 -1
- package/dist/components/Logo/Logo.types.d.ts +41 -0
- package/dist/components/Logo/Logo.types.d.ts.map +1 -0
- package/dist/components/Logo/index.d.ts +1 -1
- package/dist/components/Logo/index.d.ts.map +1 -1
- package/dist/components/Logo/logoAssets.d.ts +1 -0
- package/dist/components/Logo/logoAssets.d.ts.map +1 -0
- package/dist/components/SearchAutocomplete/SearchAutocomplete.d.ts +1 -1
- package/dist/components/SearchAutocomplete/SearchAutocomplete.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts +3 -3
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/hooks/useSelectField.d.ts +4 -4
- package/dist/hooks/useSelectField.d.ts.map +1 -1
- package/dist/icons/Icon.d.ts +1 -1
- package/dist/icons/Icon.d.ts.map +1 -1
- package/dist/index.css +2 -2
- package/dist/index.d.ts +54 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +2 -2
- package/dist/index.esm.js +184 -22
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +183 -20
- package/dist/index.js.map +1 -1
- package/dist/styles/theme-variables.css +62 -0
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Button/Button.tsx +4 -1
- package/src/components/DropdownMultiSelect/DropdownMultiSelect.tsx +271 -0
- package/src/components/DropdownMultiSelect/index.ts +2 -0
- package/src/components/Logo/Logo.tsx +65 -45
- package/src/components/Logo/Logo.types.ts +42 -0
- package/src/components/Logo/index.ts +1 -1
- package/src/components/SearchAutocomplete/SearchAutocomplete.tsx +1 -1
- package/src/components/Select/Select.tsx +21 -8
- package/src/hooks/useSelectField.ts +7 -2
- package/src/icons/Icon.tsx +1 -1
- package/src/index.ts +3 -0
- package/src/styles/index.css +0 -32
- package/src/utils/index.ts +5 -3
- package/tailwind.preset.js +23 -23
package/dist/index.js
CHANGED
|
@@ -75,13 +75,15 @@ const formatNumeric = (value) => {
|
|
|
75
75
|
};
|
|
76
76
|
/**
|
|
77
77
|
* Utility function to validate phone numbers
|
|
78
|
-
* Validates phone numbers with 1-
|
|
78
|
+
* Validates phone numbers with 1-17 digits, optionally starting with + symbol
|
|
79
79
|
* @param value - Phone number string to validate
|
|
80
80
|
* @returns Boolean indicating if the phone number is valid
|
|
81
81
|
*/
|
|
82
82
|
function isValidPhoneNumber(value) {
|
|
83
83
|
const trimmedValue = value.trim();
|
|
84
|
-
|
|
84
|
+
// Allow + at the beginning, followed by 1-17 digits
|
|
85
|
+
// Or just 1-17 digits without +
|
|
86
|
+
const phoneRegex = /^(\+\d{1,17}|\d{1,17})$/;
|
|
85
87
|
return phoneRegex.test(trimmedValue);
|
|
86
88
|
}
|
|
87
89
|
|
|
@@ -94,6 +96,7 @@ const Button = React.forwardRef(({ className, variant = "ews-primary", size = "m
|
|
|
94
96
|
warning: "bg-ews-warning text-white hover:bg-ews-warning-hover",
|
|
95
97
|
error: "bg-ews-error text-white hover:bg-ews-error-hover",
|
|
96
98
|
outline: "bg-transparent text-sm font-medium text-ews-primary hover:text-ews-primary/80",
|
|
99
|
+
ghost: "border border-ews-primary text-ews-primary hover:bg-ews-primary hover:text-white disabled:border-gray-400 disabled:text-gray-400 focus:ring-2 focus:ring-offset-2 focus:ring-ews-primary",
|
|
97
100
|
};
|
|
98
101
|
const sizes = {
|
|
99
102
|
sm: "px-3 py-1.5 text-sm",
|
|
@@ -516,7 +519,7 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
|
|
|
516
519
|
? options.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()))
|
|
517
520
|
: options;
|
|
518
521
|
// Calculate dropdown position based on available space
|
|
519
|
-
const calculateDropdownPosition = () => {
|
|
522
|
+
const calculateDropdownPosition = React.useCallback(() => {
|
|
520
523
|
if (!containerRef.current)
|
|
521
524
|
return;
|
|
522
525
|
const containerRect = containerRef.current.getBoundingClientRect();
|
|
@@ -547,7 +550,7 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
|
|
|
547
550
|
else {
|
|
548
551
|
setDropdownPosition("bottom");
|
|
549
552
|
}
|
|
550
|
-
};
|
|
553
|
+
}, [filteredOptions.length, searchable, maxHeight]);
|
|
551
554
|
// Alternative calculation using actual dropdown element when available
|
|
552
555
|
const calculateDropdownPositionWithElement = () => {
|
|
553
556
|
if (!containerRef.current || !dropdownRef.current)
|
|
@@ -597,7 +600,13 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
|
|
|
597
600
|
calculateDropdownPositionWithElement();
|
|
598
601
|
});
|
|
599
602
|
}
|
|
600
|
-
}, [
|
|
603
|
+
}, [
|
|
604
|
+
isOpen,
|
|
605
|
+
filteredOptions.length,
|
|
606
|
+
searchable,
|
|
607
|
+
maxHeight,
|
|
608
|
+
calculateDropdownPosition,
|
|
609
|
+
]);
|
|
601
610
|
// Recalculate position on window resize
|
|
602
611
|
React.useEffect(() => {
|
|
603
612
|
const handleResize = () => {
|
|
@@ -611,7 +620,7 @@ const Select = React.forwardRef(({ options = [], value, onChange, placeholder =
|
|
|
611
620
|
window.removeEventListener("resize", handleResize);
|
|
612
621
|
window.removeEventListener("scroll", handleResize);
|
|
613
622
|
};
|
|
614
|
-
}, [isOpen]);
|
|
623
|
+
}, [isOpen, calculateDropdownPosition]);
|
|
615
624
|
// Handle keyboard navigation
|
|
616
625
|
const handleKeyDown = (event) => {
|
|
617
626
|
if (disabled)
|
|
@@ -1257,6 +1266,50 @@ function useController(props) {
|
|
|
1257
1266
|
}), [field, formState, fieldState]);
|
|
1258
1267
|
}
|
|
1259
1268
|
|
|
1269
|
+
/**
|
|
1270
|
+
* Component based on `useController` hook to work with controlled component.
|
|
1271
|
+
*
|
|
1272
|
+
* @remarks
|
|
1273
|
+
* [API](https://react-hook-form.com/docs/usecontroller/controller) • [Demo](https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw) • [Video](https://www.youtube.com/watch?v=N2UNk_UCVyA)
|
|
1274
|
+
*
|
|
1275
|
+
* @param props - the path name to the form field value, and validation rules.
|
|
1276
|
+
*
|
|
1277
|
+
* @returns provide field handler functions, field and form state.
|
|
1278
|
+
*
|
|
1279
|
+
* @example
|
|
1280
|
+
* ```tsx
|
|
1281
|
+
* function App() {
|
|
1282
|
+
* const { control } = useForm<FormValues>({
|
|
1283
|
+
* defaultValues: {
|
|
1284
|
+
* test: ""
|
|
1285
|
+
* }
|
|
1286
|
+
* });
|
|
1287
|
+
*
|
|
1288
|
+
* return (
|
|
1289
|
+
* <form>
|
|
1290
|
+
* <Controller
|
|
1291
|
+
* control={control}
|
|
1292
|
+
* name="test"
|
|
1293
|
+
* render={({ field: { onChange, onBlur, value, ref }, formState, fieldState }) => (
|
|
1294
|
+
* <>
|
|
1295
|
+
* <input
|
|
1296
|
+
* onChange={onChange} // send value to hook form
|
|
1297
|
+
* onBlur={onBlur} // notify when input is touched
|
|
1298
|
+
* value={value} // return updated value
|
|
1299
|
+
* ref={ref} // set ref for focus management
|
|
1300
|
+
* />
|
|
1301
|
+
* <p>{formState.isSubmitted ? "submitted" : ""}</p>
|
|
1302
|
+
* <p>{fieldState.isTouched ? "touched" : ""}</p>
|
|
1303
|
+
* </>
|
|
1304
|
+
* )}
|
|
1305
|
+
* />
|
|
1306
|
+
* </form>
|
|
1307
|
+
* );
|
|
1308
|
+
* }
|
|
1309
|
+
* ```
|
|
1310
|
+
*/
|
|
1311
|
+
const Controller = (props) => props.render(useController(props));
|
|
1312
|
+
|
|
1260
1313
|
function useSelectField({ name, control, options: _options, rules, defaultValue, }) {
|
|
1261
1314
|
const { field, fieldState: { error, invalid }, } = useController({
|
|
1262
1315
|
name,
|
|
@@ -1593,7 +1646,90 @@ const Modal = ({ isOpen, onClose, title, children, variant = "info", primaryActi
|
|
|
1593
1646
|
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 }))] }))] })] }));
|
|
1594
1647
|
};
|
|
1595
1648
|
|
|
1596
|
-
const
|
|
1649
|
+
const DropdownMultiSelect = ({ options, name, control, placeholder = "Select options", searchPlaceholder = "Search...", onChange, value: controlledValue, defaultValue, onValidate, disabled = false, error, label, className, }) => {
|
|
1650
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
1651
|
+
const [searchTerm, setSearchTerm] = React.useState("");
|
|
1652
|
+
const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
|
|
1653
|
+
const dropdownRef = React.useRef(null);
|
|
1654
|
+
const handleToggle = () => {
|
|
1655
|
+
if (!disabled) {
|
|
1656
|
+
setIsOpen(!isOpen);
|
|
1657
|
+
}
|
|
1658
|
+
};
|
|
1659
|
+
const handleClickOutside = (event) => {
|
|
1660
|
+
if (dropdownRef.current &&
|
|
1661
|
+
!dropdownRef.current.contains(event.target)) {
|
|
1662
|
+
setIsOpen(false);
|
|
1663
|
+
setSearchTerm("");
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
React.useEffect(() => {
|
|
1667
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1668
|
+
return () => {
|
|
1669
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
1670
|
+
};
|
|
1671
|
+
}, []);
|
|
1672
|
+
const removeAccents = (str) => str
|
|
1673
|
+
.normalize("NFD")
|
|
1674
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
1675
|
+
.replace(/ç/g, "c")
|
|
1676
|
+
.replace(/é|è|ê|ë/g, "e")
|
|
1677
|
+
.replace(/à|á|â|ã|ä/g, "a")
|
|
1678
|
+
.replace(/î|ï/g, "i")
|
|
1679
|
+
.replace(/ô|ö/g, "o")
|
|
1680
|
+
.replace(/ù|ú|û|ü/g, "u");
|
|
1681
|
+
const getDisplayValue = (value) => {
|
|
1682
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1683
|
+
return String(value);
|
|
1684
|
+
}
|
|
1685
|
+
return options.find((opt) => opt.value === value)?.label || "";
|
|
1686
|
+
};
|
|
1687
|
+
const filteredOptions = options.filter((option) => removeAccents(option.label.toLowerCase()).includes(removeAccents(searchTerm.toLowerCase())));
|
|
1688
|
+
const renderDropdown = ({ value = [], onChange: fieldOnChange, }) => (jsxRuntime.jsxs("div", { className: cn("relative", className), ref: dropdownRef, children: [jsxRuntime.jsxs("button", { type: "button", onClick: handleToggle, "aria-label": name, disabled: disabled, className: cn("flex w-full items-center justify-between rounded-md border border-ews-gray-300 bg-white px-3 py-2 text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-ews-primary focus:ring-offset-0 disabled:bg-ews-gray-50 disabled:text-ews-gray-500", isOpen ? "rounded-b-none border-b-0" : "rounded-md", error && "border-ews-error focus:ring-ews-error"), children: [jsxRuntime.jsx("span", { className: cn("truncate", !value?.length && "text-ews-gray-500"), children: value?.length > 0
|
|
1689
|
+
? value.map((v) => getDisplayValue(v)).join(", ")
|
|
1690
|
+
: placeholder }), jsxRuntime.jsx("span", { className: cn("ml-2 w-4 h-4 transition-transform transform", isOpen ? "rotate-180" : "rotate-0"), children: jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) }) })] }), isOpen && (jsxRuntime.jsxs("div", { className: "absolute z-50 w-full bg-white rounded-b-md border border-t-0 shadow-lg border-ews-gray-300", children: [jsxRuntime.jsx("div", { className: "p-2 border-b border-ews-gray-200", children: jsxRuntime.jsx(Input, { type: "text", placeholder: searchPlaceholder, value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "p-0 border-0 shadow-none focus:ring-0", size: "sm" }) }), jsxRuntime.jsx("div", { className: "overflow-y-auto max-h-48", children: filteredOptions.length > 0 ? (filteredOptions.map((option) => (jsxRuntime.jsxs("div", { className: "flex items-center p-2 cursor-pointer hover:bg-ews-gray-100", onClick: () => {
|
|
1691
|
+
const currentValue = value ?? [];
|
|
1692
|
+
const isSelected = currentValue.some((item) => JSON.stringify(item) === JSON.stringify(option.value));
|
|
1693
|
+
const newValue = isSelected
|
|
1694
|
+
? currentValue.filter((item) => JSON.stringify(item) !==
|
|
1695
|
+
JSON.stringify(option.value))
|
|
1696
|
+
: [...currentValue, option.value];
|
|
1697
|
+
if (onValidate && !onValidate(newValue)) {
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
fieldOnChange(newValue);
|
|
1701
|
+
onChange?.(newValue);
|
|
1702
|
+
}, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: (value ?? []).some((item) => JSON.stringify(item) === JSON.stringify(option.value)), onChange: (e) => {
|
|
1703
|
+
e.stopPropagation();
|
|
1704
|
+
const currentValue = value ?? [];
|
|
1705
|
+
const isSelected = currentValue.some((item) => JSON.stringify(item) === JSON.stringify(option.value));
|
|
1706
|
+
const newValue = isSelected
|
|
1707
|
+
? currentValue.filter((item) => JSON.stringify(item) !==
|
|
1708
|
+
JSON.stringify(option.value))
|
|
1709
|
+
: [...currentValue, option.value];
|
|
1710
|
+
if (onValidate && !onValidate(newValue)) {
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
fieldOnChange(newValue);
|
|
1714
|
+
onChange?.(newValue);
|
|
1715
|
+
}, onClick: (e) => e.stopPropagation(), className: "mr-3 w-4 h-4 rounded border-ews-gray-300 text-ews-primary focus:ring-ews-primary" }), jsxRuntime.jsx("label", { className: "text-sm cursor-pointer text-ews-gray-700", children: option.label })] }, getDisplayValue(option.value))))) : (jsxRuntime.jsx("div", { className: "p-2 text-sm text-ews-gray-500", children: "No options found" })) })] }))] }));
|
|
1716
|
+
// Render controlled version with react-hook-form
|
|
1717
|
+
if (control) {
|
|
1718
|
+
return (jsxRuntime.jsx(Controller, { name: name, control: control, render: ({ field: { value, onChange } }) => (jsxRuntime.jsxs("div", { children: [label && (jsxRuntime.jsx("label", { className: "block mb-1 text-sm font-medium text-ews-gray-700", children: label })), renderDropdown({ value, onChange }), error && jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ews-error", children: error })] })) }));
|
|
1719
|
+
}
|
|
1720
|
+
// Render uncontrolled version
|
|
1721
|
+
return (jsxRuntime.jsxs("div", { children: [label && (jsxRuntime.jsx("label", { className: "block mb-1 text-sm font-medium text-ews-gray-700", children: label })), renderDropdown({
|
|
1722
|
+
value: controlledValue ?? uncontrolledValue,
|
|
1723
|
+
onChange: (newValue) => {
|
|
1724
|
+
if (controlledValue === undefined) {
|
|
1725
|
+
setUncontrolledValue(newValue);
|
|
1726
|
+
}
|
|
1727
|
+
onChange?.(newValue);
|
|
1728
|
+
},
|
|
1729
|
+
}), error && jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ews-error", children: error })] }));
|
|
1730
|
+
};
|
|
1731
|
+
|
|
1732
|
+
const Logo = ({ size = "md", showTagline: _showTagline = true, iconOnly = false, variant = "normal", className, onClick, customSrc, alt = "MEDECINE 360 Logo", clickable = false, }) => {
|
|
1597
1733
|
const sizes = {
|
|
1598
1734
|
sm: "h-8",
|
|
1599
1735
|
md: "h-12",
|
|
@@ -1606,21 +1742,47 @@ const Logo = ({ size = "md", showTagline: _showTagline = true, iconOnly = false,
|
|
|
1606
1742
|
lg: "h-12 w-12",
|
|
1607
1743
|
xl: "h-16 w-16",
|
|
1608
1744
|
};
|
|
1609
|
-
// Get the appropriate logo image based on variant
|
|
1610
|
-
// For iconOnly, always use favicon.ico
|
|
1611
|
-
const logoSrc =
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1745
|
+
// Get the appropriate logo image based on variant or custom source
|
|
1746
|
+
// For iconOnly, always use favicon.ico unless customSrc is provided
|
|
1747
|
+
const logoSrc = customSrc ||
|
|
1748
|
+
(iconOnly
|
|
1749
|
+
? "/favicon.ico"
|
|
1750
|
+
: variant === "white"
|
|
1751
|
+
? "/image/logoWhite.png"
|
|
1752
|
+
: variant === "fullWhite"
|
|
1753
|
+
? "/image/logoFullWhite.png"
|
|
1754
|
+
: variant === "favicon"
|
|
1755
|
+
? "/favicon.ico"
|
|
1756
|
+
: "/image/logo.png");
|
|
1757
|
+
const isClickable = clickable || !!onClick;
|
|
1620
1758
|
if (iconOnly) {
|
|
1621
|
-
return (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center", iconSizes[size], className), onClick: onClick, role:
|
|
1759
|
+
return (jsxRuntime.jsx("div", { className: cn("flex items-center justify-center", iconSizes[size], isClickable && "cursor-pointer", className), onClick: onClick, role: isClickable ? "button" : undefined, tabIndex: isClickable ? 0 : undefined, onKeyDown: isClickable
|
|
1760
|
+
? (e) => {
|
|
1761
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1762
|
+
e.preventDefault();
|
|
1763
|
+
onClick?.();
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
: undefined, children: jsxRuntime.jsx("img", { src: logoSrc, alt: alt, className: "object-contain w-full h-full", onError: (e) => {
|
|
1767
|
+
// Fallback to favicon if image fails to load
|
|
1768
|
+
if (logoSrc !== "/favicon.ico") {
|
|
1769
|
+
e.target.src = "/favicon.ico";
|
|
1770
|
+
}
|
|
1771
|
+
} }) }));
|
|
1622
1772
|
}
|
|
1623
|
-
return (jsxRuntime.jsx("div", { className: cn("flex items-center", sizes[size], className), onClick: onClick, role:
|
|
1773
|
+
return (jsxRuntime.jsx("div", { className: cn("flex items-center", sizes[size], isClickable && "cursor-pointer", className), onClick: onClick, role: isClickable ? "button" : undefined, tabIndex: isClickable ? 0 : undefined, onKeyDown: isClickable
|
|
1774
|
+
? (e) => {
|
|
1775
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1776
|
+
e.preventDefault();
|
|
1777
|
+
onClick?.();
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
: undefined, children: jsxRuntime.jsx("img", { src: logoSrc, alt: alt, className: "object-contain w-auto h-full", onError: (e) => {
|
|
1781
|
+
// Fallback to favicon if image fails to load
|
|
1782
|
+
if (logoSrc !== "/favicon.ico") {
|
|
1783
|
+
e.target.src = "/favicon.ico";
|
|
1784
|
+
}
|
|
1785
|
+
} }) }));
|
|
1624
1786
|
};
|
|
1625
1787
|
|
|
1626
1788
|
const PROMED_THEME = {
|
|
@@ -1792,6 +1954,7 @@ exports.ArrowRight = ArrowRight;
|
|
|
1792
1954
|
exports.Button = Button;
|
|
1793
1955
|
exports.Check = Check;
|
|
1794
1956
|
exports.DoctorIcon = DoctorIcon;
|
|
1957
|
+
exports.DropdownMultiSelect = DropdownMultiSelect;
|
|
1795
1958
|
exports.Icon = Icon;
|
|
1796
1959
|
exports.Input = Input;
|
|
1797
1960
|
exports.Logo = Logo;
|