infinity-ui-elements 1.8.8 → 1.8.10
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/DatePicker/DatePicker.d.ts +124 -0
- package/dist/components/DatePicker/DatePicker.d.ts.map +1 -0
- package/dist/components/DatePicker/DatePicker.stories.d.ts +26 -0
- package/dist/components/DatePicker/DatePicker.stories.d.ts.map +1 -0
- package/dist/components/DatePicker/index.d.ts +3 -0
- package/dist/components/DatePicker/index.d.ts.map +1 -0
- package/dist/components/SearchableDropdown/SearchableDropdown.stories.d.ts +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +586 -354
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +586 -352
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.esm.js
CHANGED
|
@@ -5,7 +5,9 @@ import { Slot } from '@radix-ui/react-slot';
|
|
|
5
5
|
import { PulseLoader, ClipLoader } from 'react-spinners';
|
|
6
6
|
import { clsx } from 'clsx';
|
|
7
7
|
import { twMerge } from 'tailwind-merge';
|
|
8
|
-
import { ExternalLink, Loader2, Search, ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react';
|
|
8
|
+
import { ExternalLink, Calendar, Loader2, Search, ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react';
|
|
9
|
+
import Calendar$1 from 'react-calendar';
|
|
10
|
+
import 'react-calendar/dist/Calendar.css';
|
|
9
11
|
import { createPortal } from 'react-dom';
|
|
10
12
|
import { flexRender } from '@tanstack/react-table';
|
|
11
13
|
|
|
@@ -1688,374 +1690,113 @@ const Counter = React.forwardRef(({ value, max, size = "medium", color = "neutra
|
|
|
1688
1690
|
});
|
|
1689
1691
|
Counter.displayName = "Counter";
|
|
1690
1692
|
|
|
1691
|
-
const
|
|
1693
|
+
const tooltipVariants = cva("fixed z-50 bg-popup-fill-intense text-action-ink-on-primary-normal rounded-medium border border-popup-outline-subtle flex flex-col p-4 rounded-xlarge min-w-[200px] max-w-[300px] transition-opacity duration-200", {
|
|
1692
1694
|
variants: {
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
},
|
|
1697
|
-
thickness: {
|
|
1698
|
-
thinner: "",
|
|
1699
|
-
thin: "",
|
|
1700
|
-
thick: "",
|
|
1701
|
-
thicker: "",
|
|
1702
|
-
},
|
|
1703
|
-
lineStyle: {
|
|
1704
|
-
solid: "border-solid",
|
|
1705
|
-
dashed: "border-dashed",
|
|
1706
|
-
},
|
|
1707
|
-
variant: {
|
|
1708
|
-
normal: "",
|
|
1709
|
-
subtle: "",
|
|
1710
|
-
muted: "",
|
|
1695
|
+
isVisible: {
|
|
1696
|
+
true: "opacity-100 pointer-events-auto shadow-[0_4px_20px_rgba(0,0,0,0.15)]",
|
|
1697
|
+
false: "opacity-0 pointer-events-none",
|
|
1711
1698
|
},
|
|
1712
1699
|
},
|
|
1713
|
-
compoundVariants: [
|
|
1714
|
-
// Horizontal orientation with thickness
|
|
1715
|
-
{
|
|
1716
|
-
orientation: "horizontal",
|
|
1717
|
-
thickness: "thinner",
|
|
1718
|
-
class: "border-t-[0.5px]",
|
|
1719
|
-
},
|
|
1720
|
-
{
|
|
1721
|
-
orientation: "horizontal",
|
|
1722
|
-
thickness: "thin",
|
|
1723
|
-
class: "border-t-[1px]",
|
|
1724
|
-
},
|
|
1725
|
-
{
|
|
1726
|
-
orientation: "horizontal",
|
|
1727
|
-
thickness: "thick",
|
|
1728
|
-
class: "border-t-[2px]",
|
|
1729
|
-
},
|
|
1730
|
-
{
|
|
1731
|
-
orientation: "horizontal",
|
|
1732
|
-
thickness: "thicker",
|
|
1733
|
-
class: "border-t-[3px]",
|
|
1734
|
-
},
|
|
1735
|
-
// Vertical orientation with thickness
|
|
1736
|
-
{
|
|
1737
|
-
orientation: "vertical",
|
|
1738
|
-
thickness: "thinner",
|
|
1739
|
-
class: "border-l-[0.5px]",
|
|
1740
|
-
},
|
|
1741
|
-
{
|
|
1742
|
-
orientation: "vertical",
|
|
1743
|
-
thickness: "thin",
|
|
1744
|
-
class: "border-l-[1px]",
|
|
1745
|
-
},
|
|
1746
|
-
{
|
|
1747
|
-
orientation: "vertical",
|
|
1748
|
-
thickness: "thick",
|
|
1749
|
-
class: "border-l-[2px]",
|
|
1750
|
-
},
|
|
1751
|
-
{
|
|
1752
|
-
orientation: "vertical",
|
|
1753
|
-
thickness: "thicker",
|
|
1754
|
-
class: "border-l-[3px]",
|
|
1755
|
-
},
|
|
1756
|
-
// Normal variant colors
|
|
1757
|
-
{
|
|
1758
|
-
variant: "normal",
|
|
1759
|
-
class: "border-surface-outline-neutral-normal",
|
|
1760
|
-
},
|
|
1761
|
-
// Subtle variant colors
|
|
1762
|
-
{
|
|
1763
|
-
variant: "subtle",
|
|
1764
|
-
class: "border-surface-outline-neutral-subtle",
|
|
1765
|
-
},
|
|
1766
|
-
// Muted variant colors
|
|
1767
|
-
{
|
|
1768
|
-
variant: "muted",
|
|
1769
|
-
class: "border-surface-outline-neutral-muted",
|
|
1770
|
-
},
|
|
1771
|
-
],
|
|
1772
1700
|
defaultVariants: {
|
|
1773
|
-
|
|
1774
|
-
thickness: "thin",
|
|
1775
|
-
lineStyle: "solid",
|
|
1776
|
-
variant: "normal",
|
|
1701
|
+
isVisible: false,
|
|
1777
1702
|
},
|
|
1778
1703
|
});
|
|
1779
|
-
const
|
|
1780
|
-
return (jsx("div", { ref: ref, role: "separator", "aria-orientation": orientation, className: cn(dividerVariants({ orientation, thickness, lineStyle, variant }), className), ...props }));
|
|
1781
|
-
});
|
|
1782
|
-
Divider.displayName = "Divider";
|
|
1783
|
-
|
|
1784
|
-
const listItemVariants = cva("flex items-start gap-3 p-3 rounded-medium transition-colors cursor-pointer", {
|
|
1704
|
+
const tooltipArrowVariants = cva("absolute w-0 h-0 border-solid border-[6px] -translate-x-1/2", {
|
|
1785
1705
|
variants: {
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
bordered: "border border-action-outline-primary-faded hover:bg-surface-fill-primary-subtle",
|
|
1794
|
-
primary: `hover:bg-action-fill-neutral-faded
|
|
1795
|
-
focus:bg-action-fill-neutral-faded
|
|
1796
|
-
focus:ring-2
|
|
1797
|
-
ring-action-outline-primary-faded-hover
|
|
1798
|
-
border border-transparent
|
|
1799
|
-
`,
|
|
1800
|
-
negative: `hover:bg-action-fill-negative-faded
|
|
1801
|
-
focus:bg-action-fill-negative-faded
|
|
1802
|
-
focus:ring-2 ring-action-outline-negative-faded-hover
|
|
1803
|
-
border border-transparent
|
|
1804
|
-
`,
|
|
1805
|
-
},
|
|
1806
|
-
isDisabled: {
|
|
1807
|
-
true: "cursor-not-allowed opacity-60",
|
|
1808
|
-
false: "",
|
|
1809
|
-
},
|
|
1810
|
-
isSelected: {
|
|
1811
|
-
true: "bg-action-fill-primary-faded border-action-outline-primary-faded",
|
|
1812
|
-
false: "",
|
|
1706
|
+
placement: {
|
|
1707
|
+
"top-start": "top-full border-t-popup-fill-intense border-x-transparent border-b-transparent",
|
|
1708
|
+
top: "top-full border-t-popup-fill-intense border-x-transparent border-b-transparent",
|
|
1709
|
+
"top-end": "top-full border-t-popup-fill-intense border-x-transparent border-b-transparent",
|
|
1710
|
+
"bottom-start": "bottom-full border-b-popup-fill-intense border-x-transparent border-t-transparent",
|
|
1711
|
+
bottom: "bottom-full border-b-popup-fill-intense border-x-transparent border-t-transparent",
|
|
1712
|
+
"bottom-end": "bottom-full border-b-popup-fill-intense border-x-transparent border-t-transparent",
|
|
1813
1713
|
},
|
|
1814
1714
|
},
|
|
1815
1715
|
defaultVariants: {
|
|
1816
|
-
|
|
1817
|
-
isDisabled: false,
|
|
1818
|
-
isSelected: false,
|
|
1716
|
+
placement: "top",
|
|
1819
1717
|
},
|
|
1820
1718
|
});
|
|
1821
|
-
const
|
|
1822
|
-
const
|
|
1823
|
-
const [
|
|
1824
|
-
|
|
1825
|
-
React.
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
const
|
|
1829
|
-
|
|
1719
|
+
const Tooltip = React.forwardRef(({ children, heading, description, placement = "top", showArrow = true, className, delay = 200, disabled = false, }, ref) => {
|
|
1720
|
+
const [isVisible, setIsVisible] = React.useState(false);
|
|
1721
|
+
const [position, setPosition] = React.useState({ top: 0, left: 0 });
|
|
1722
|
+
const [arrowPosition, setArrowPosition] = React.useState({ left: 0 });
|
|
1723
|
+
const [actualPlacement, setActualPlacement] = React.useState(placement);
|
|
1724
|
+
const timeoutRef = React.useRef(null);
|
|
1725
|
+
const triggerRef = React.useRef(null);
|
|
1726
|
+
const tooltipRef = React.useRef(null);
|
|
1727
|
+
const calculatePosition = React.useCallback(() => {
|
|
1728
|
+
if (!triggerRef.current || !tooltipRef.current)
|
|
1830
1729
|
return;
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1730
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
1731
|
+
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
1732
|
+
const gap = 8; // 8px gap between trigger and tooltip
|
|
1733
|
+
const arrowSize = 6; // Size of the arrow
|
|
1734
|
+
const viewportPadding = 8; // Minimum padding from viewport edges
|
|
1735
|
+
let top = 0;
|
|
1736
|
+
let left = 0;
|
|
1737
|
+
let currentPlacement = placement;
|
|
1738
|
+
// Calculate initial position based on placement
|
|
1739
|
+
switch (placement) {
|
|
1740
|
+
case "top-start":
|
|
1741
|
+
top = triggerRect.top - tooltipRect.height - gap - arrowSize;
|
|
1742
|
+
left = triggerRect.left;
|
|
1743
|
+
break;
|
|
1744
|
+
case "top":
|
|
1745
|
+
top = triggerRect.top - tooltipRect.height - gap - arrowSize;
|
|
1746
|
+
left =
|
|
1747
|
+
triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
1748
|
+
break;
|
|
1749
|
+
case "top-end":
|
|
1750
|
+
top = triggerRect.top - tooltipRect.height - gap - arrowSize;
|
|
1751
|
+
left = triggerRect.right - tooltipRect.width;
|
|
1752
|
+
break;
|
|
1753
|
+
case "bottom-start":
|
|
1754
|
+
top = triggerRect.bottom + gap + arrowSize;
|
|
1755
|
+
left = triggerRect.left;
|
|
1756
|
+
break;
|
|
1757
|
+
case "bottom":
|
|
1758
|
+
top = triggerRect.bottom + gap + arrowSize;
|
|
1759
|
+
left =
|
|
1760
|
+
triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
1761
|
+
break;
|
|
1762
|
+
case "bottom-end":
|
|
1763
|
+
top = triggerRect.bottom + gap + arrowSize;
|
|
1764
|
+
left = triggerRect.right - tooltipRect.width;
|
|
1765
|
+
break;
|
|
1835
1766
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
if (
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
setInternalSelected(newSelected);
|
|
1844
|
-
onSelectionChange?.(newSelected);
|
|
1845
|
-
};
|
|
1846
|
-
return (jsxs("div", { ref: ref, className: cn(listItemVariants({
|
|
1847
|
-
variant,
|
|
1848
|
-
isDisabled,
|
|
1849
|
-
isSelected: type === "multiple" ? internalSelected : false,
|
|
1850
|
-
}), containerClassName), onClick: handleClick, role: type === "multiple" ? "checkbox" : "button", "aria-checked": type === "multiple" ? internalSelected : undefined, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, ...props, children: [type === "multiple" && (jsx(Checkbox, { checked: internalSelected, onChange: handleCheckboxChange, isDisabled: isDisabled, size: checkboxSize, className: "shrink-0 mt-0.5" })), leadingIcon && (jsx("div", { className: cn(`shrink-0 flex items-center justify-center mt-0.5`, variant === "primary"
|
|
1851
|
-
? "text-action-ink-primary-normal"
|
|
1852
|
-
: variant === "negative"
|
|
1853
|
-
? "text-action-ink-negative-normal"
|
|
1854
|
-
: "text-action-ink-neutral-subtle", isDisabled && "text-surface-ink-neutral-disabled"), children: leadingIcon })), jsxs("div", { className: cn("flex-1 min-w-0 flex flex-col justify-center", contentClassName), children: [jsx("div", { className: cn("text-body-medium-regular truncate", variant === "primary"
|
|
1855
|
-
? "text-action-ink-primary-normal"
|
|
1856
|
-
: variant === "negative"
|
|
1857
|
-
? "text-action-ink-negative-normal"
|
|
1858
|
-
: "text-action-ink-neutral-normal", isDisabled && "text-surface-ink-neutral-disabled"), children: title }), description && (jsx("div", { className: cn("text-body-small-regular text-surface-ink-neutral-muted mt-0.5 line-clamp-2", isDisabled && "text-surface-ink-neutral-disabled"), children: description }))] }), (trailingIcon || showChevron) && (jsx("div", { className: "shrink-0 self-center text-action-ink-neutral-subtle", children: trailingIcon || jsx(ChevronRightIcon, {}) }))] }));
|
|
1859
|
-
});
|
|
1860
|
-
ListItem.displayName = "ListItem";
|
|
1861
|
-
|
|
1862
|
-
const DropdownMenu = React.forwardRef(({ items = [], customContent, sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, showChevron = false, emptyIcon, disableFooter = false, showFooter, footerLayout = "horizontal", onClose, focusedIndex = -1, className, width = "auto", }, ref) => {
|
|
1863
|
-
const renderContent = () => {
|
|
1864
|
-
if (isLoading) {
|
|
1865
|
-
return (jsx("div", { className: "flex flex-col items-center justify-center py-12 px-6", children: jsx(Loader2, { className: "w-12 h-12 text-action-ink-primary-normal mb-4 animate-spin" }) }));
|
|
1767
|
+
// Get viewport dimensions
|
|
1768
|
+
const viewportWidth = window.innerWidth;
|
|
1769
|
+
const viewportHeight = window.innerHeight;
|
|
1770
|
+
// Adjust horizontal position to keep tooltip within viewport
|
|
1771
|
+
if (left < viewportPadding) {
|
|
1772
|
+
// Tooltip would overflow on the left
|
|
1773
|
+
left = viewportPadding;
|
|
1866
1774
|
}
|
|
1867
|
-
if (
|
|
1868
|
-
|
|
1775
|
+
else if (left + tooltipRect.width > viewportWidth - viewportPadding) {
|
|
1776
|
+
// Tooltip would overflow on the right
|
|
1777
|
+
left = viewportWidth - tooltipRect.width - viewportPadding;
|
|
1869
1778
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
size: {
|
|
1892
|
-
small: "w-64",
|
|
1893
|
-
medium: "w-80",
|
|
1894
|
-
large: "w-96",
|
|
1895
|
-
},
|
|
1896
|
-
},
|
|
1897
|
-
defaultVariants: {
|
|
1898
|
-
size: "medium",
|
|
1899
|
-
},
|
|
1900
|
-
});
|
|
1901
|
-
const Dropdown = React.forwardRef(({ className, trigger, items = [], customContent, sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, size = "medium", open: controlledOpen, defaultOpen = false, onOpenChange, containerClassName, menuClassName, showChevron = false, emptyIcon, disableFooter = false, showFooter, ...props }, ref) => {
|
|
1902
|
-
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
1903
|
-
const isOpen = controlledOpen !== undefined ? controlledOpen : uncontrolledOpen;
|
|
1904
|
-
const dropdownRef = React.useRef(null);
|
|
1905
|
-
const handleOpenChange = (newOpen) => {
|
|
1906
|
-
if (controlledOpen === undefined) {
|
|
1907
|
-
setUncontrolledOpen(newOpen);
|
|
1908
|
-
}
|
|
1909
|
-
onOpenChange?.(newOpen);
|
|
1910
|
-
};
|
|
1911
|
-
const toggleOpen = () => {
|
|
1912
|
-
handleOpenChange(!isOpen);
|
|
1913
|
-
};
|
|
1914
|
-
// Close dropdown when clicking outside
|
|
1915
|
-
React.useEffect(() => {
|
|
1916
|
-
const handleClickOutside = (event) => {
|
|
1917
|
-
if (dropdownRef.current &&
|
|
1918
|
-
!dropdownRef.current.contains(event.target)) {
|
|
1919
|
-
handleOpenChange(false);
|
|
1920
|
-
}
|
|
1921
|
-
};
|
|
1922
|
-
if (isOpen) {
|
|
1923
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
1924
|
-
return () => {
|
|
1925
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
1926
|
-
};
|
|
1927
|
-
}
|
|
1928
|
-
}, [isOpen]);
|
|
1929
|
-
// Close on escape key
|
|
1930
|
-
React.useEffect(() => {
|
|
1931
|
-
const handleEscape = (event) => {
|
|
1932
|
-
if (event.key === "Escape") {
|
|
1933
|
-
handleOpenChange(false);
|
|
1934
|
-
}
|
|
1935
|
-
};
|
|
1936
|
-
if (isOpen) {
|
|
1937
|
-
document.addEventListener("keydown", handleEscape);
|
|
1938
|
-
return () => {
|
|
1939
|
-
document.removeEventListener("keydown", handleEscape);
|
|
1940
|
-
};
|
|
1941
|
-
}
|
|
1942
|
-
}, [isOpen]);
|
|
1943
|
-
const sizeMap = {
|
|
1944
|
-
small: "w-64",
|
|
1945
|
-
medium: "w-80",
|
|
1946
|
-
large: "w-96",
|
|
1947
|
-
};
|
|
1948
|
-
return (jsxs("div", { ref: dropdownRef, className: cn("relative inline-block", containerClassName), ...props, children: [trigger && (jsx("div", { onClick: toggleOpen, className: "cursor-pointer", children: trigger })), isOpen && (jsx(DropdownMenu, { ref: ref, items: items, customContent: customContent, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: isEmpty, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, showFooter: showFooter, onClose: () => handleOpenChange(false), className: cn("absolute z-50 mt-2", menuClassName, className), width: sizeMap[size] }))] }));
|
|
1949
|
-
});
|
|
1950
|
-
Dropdown.displayName = "Dropdown";
|
|
1951
|
-
|
|
1952
|
-
const tooltipVariants = cva("fixed z-50 bg-popup-fill-intense text-action-ink-on-primary-normal rounded-medium border border-popup-outline-subtle flex flex-col p-4 rounded-xlarge min-w-[200px] max-w-[300px] transition-opacity duration-200", {
|
|
1953
|
-
variants: {
|
|
1954
|
-
isVisible: {
|
|
1955
|
-
true: "opacity-100 pointer-events-auto shadow-[0_4px_20px_rgba(0,0,0,0.15)]",
|
|
1956
|
-
false: "opacity-0 pointer-events-none",
|
|
1957
|
-
},
|
|
1958
|
-
},
|
|
1959
|
-
defaultVariants: {
|
|
1960
|
-
isVisible: false,
|
|
1961
|
-
},
|
|
1962
|
-
});
|
|
1963
|
-
const tooltipArrowVariants = cva("absolute w-0 h-0 border-solid border-[6px] -translate-x-1/2", {
|
|
1964
|
-
variants: {
|
|
1965
|
-
placement: {
|
|
1966
|
-
"top-start": "top-full border-t-popup-fill-intense border-x-transparent border-b-transparent",
|
|
1967
|
-
top: "top-full border-t-popup-fill-intense border-x-transparent border-b-transparent",
|
|
1968
|
-
"top-end": "top-full border-t-popup-fill-intense border-x-transparent border-b-transparent",
|
|
1969
|
-
"bottom-start": "bottom-full border-b-popup-fill-intense border-x-transparent border-t-transparent",
|
|
1970
|
-
bottom: "bottom-full border-b-popup-fill-intense border-x-transparent border-t-transparent",
|
|
1971
|
-
"bottom-end": "bottom-full border-b-popup-fill-intense border-x-transparent border-t-transparent",
|
|
1972
|
-
},
|
|
1973
|
-
},
|
|
1974
|
-
defaultVariants: {
|
|
1975
|
-
placement: "top",
|
|
1976
|
-
},
|
|
1977
|
-
});
|
|
1978
|
-
const Tooltip = React.forwardRef(({ children, heading, description, placement = "top", showArrow = true, className, delay = 200, disabled = false, }, ref) => {
|
|
1979
|
-
const [isVisible, setIsVisible] = React.useState(false);
|
|
1980
|
-
const [position, setPosition] = React.useState({ top: 0, left: 0 });
|
|
1981
|
-
const [arrowPosition, setArrowPosition] = React.useState({ left: 0 });
|
|
1982
|
-
const [actualPlacement, setActualPlacement] = React.useState(placement);
|
|
1983
|
-
const timeoutRef = React.useRef(null);
|
|
1984
|
-
const triggerRef = React.useRef(null);
|
|
1985
|
-
const tooltipRef = React.useRef(null);
|
|
1986
|
-
const calculatePosition = React.useCallback(() => {
|
|
1987
|
-
if (!triggerRef.current || !tooltipRef.current)
|
|
1988
|
-
return;
|
|
1989
|
-
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
1990
|
-
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
1991
|
-
const gap = 8; // 8px gap between trigger and tooltip
|
|
1992
|
-
const arrowSize = 6; // Size of the arrow
|
|
1993
|
-
const viewportPadding = 8; // Minimum padding from viewport edges
|
|
1994
|
-
let top = 0;
|
|
1995
|
-
let left = 0;
|
|
1996
|
-
let currentPlacement = placement;
|
|
1997
|
-
// Calculate initial position based on placement
|
|
1998
|
-
switch (placement) {
|
|
1999
|
-
case "top-start":
|
|
2000
|
-
top = triggerRect.top - tooltipRect.height - gap - arrowSize;
|
|
2001
|
-
left = triggerRect.left;
|
|
2002
|
-
break;
|
|
2003
|
-
case "top":
|
|
2004
|
-
top = triggerRect.top - tooltipRect.height - gap - arrowSize;
|
|
2005
|
-
left =
|
|
2006
|
-
triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
2007
|
-
break;
|
|
2008
|
-
case "top-end":
|
|
2009
|
-
top = triggerRect.top - tooltipRect.height - gap - arrowSize;
|
|
2010
|
-
left = triggerRect.right - tooltipRect.width;
|
|
2011
|
-
break;
|
|
2012
|
-
case "bottom-start":
|
|
2013
|
-
top = triggerRect.bottom + gap + arrowSize;
|
|
2014
|
-
left = triggerRect.left;
|
|
2015
|
-
break;
|
|
2016
|
-
case "bottom":
|
|
2017
|
-
top = triggerRect.bottom + gap + arrowSize;
|
|
2018
|
-
left =
|
|
2019
|
-
triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
|
|
2020
|
-
break;
|
|
2021
|
-
case "bottom-end":
|
|
2022
|
-
top = triggerRect.bottom + gap + arrowSize;
|
|
2023
|
-
left = triggerRect.right - tooltipRect.width;
|
|
2024
|
-
break;
|
|
2025
|
-
}
|
|
2026
|
-
// Get viewport dimensions
|
|
2027
|
-
const viewportWidth = window.innerWidth;
|
|
2028
|
-
const viewportHeight = window.innerHeight;
|
|
2029
|
-
// Adjust horizontal position to keep tooltip within viewport
|
|
2030
|
-
if (left < viewportPadding) {
|
|
2031
|
-
// Tooltip would overflow on the left
|
|
2032
|
-
left = viewportPadding;
|
|
2033
|
-
}
|
|
2034
|
-
else if (left + tooltipRect.width > viewportWidth - viewportPadding) {
|
|
2035
|
-
// Tooltip would overflow on the right
|
|
2036
|
-
left = viewportWidth - tooltipRect.width - viewportPadding;
|
|
2037
|
-
}
|
|
2038
|
-
// Adjust vertical position to keep tooltip within viewport
|
|
2039
|
-
if (top < viewportPadding) {
|
|
2040
|
-
// Tooltip would overflow at the top
|
|
2041
|
-
// Try to flip to bottom if there's more space there
|
|
2042
|
-
const spaceBelow = viewportHeight - triggerRect.bottom;
|
|
2043
|
-
const spaceAbove = triggerRect.top;
|
|
2044
|
-
if (spaceBelow > spaceAbove) {
|
|
2045
|
-
// Flip to bottom
|
|
2046
|
-
top = triggerRect.bottom + gap + arrowSize;
|
|
2047
|
-
// Update placement to reflect the flip
|
|
2048
|
-
if (placement === "top-start")
|
|
2049
|
-
currentPlacement = "bottom-start";
|
|
2050
|
-
else if (placement === "top")
|
|
2051
|
-
currentPlacement = "bottom";
|
|
2052
|
-
else if (placement === "top-end")
|
|
2053
|
-
currentPlacement = "bottom-end";
|
|
2054
|
-
}
|
|
2055
|
-
else {
|
|
2056
|
-
// Keep at top but adjust to stay in viewport
|
|
2057
|
-
top = viewportPadding;
|
|
2058
|
-
}
|
|
1779
|
+
// Adjust vertical position to keep tooltip within viewport
|
|
1780
|
+
if (top < viewportPadding) {
|
|
1781
|
+
// Tooltip would overflow at the top
|
|
1782
|
+
// Try to flip to bottom if there's more space there
|
|
1783
|
+
const spaceBelow = viewportHeight - triggerRect.bottom;
|
|
1784
|
+
const spaceAbove = triggerRect.top;
|
|
1785
|
+
if (spaceBelow > spaceAbove) {
|
|
1786
|
+
// Flip to bottom
|
|
1787
|
+
top = triggerRect.bottom + gap + arrowSize;
|
|
1788
|
+
// Update placement to reflect the flip
|
|
1789
|
+
if (placement === "top-start")
|
|
1790
|
+
currentPlacement = "bottom-start";
|
|
1791
|
+
else if (placement === "top")
|
|
1792
|
+
currentPlacement = "bottom";
|
|
1793
|
+
else if (placement === "top-end")
|
|
1794
|
+
currentPlacement = "bottom-end";
|
|
1795
|
+
}
|
|
1796
|
+
else {
|
|
1797
|
+
// Keep at top but adjust to stay in viewport
|
|
1798
|
+
top = viewportPadding;
|
|
1799
|
+
}
|
|
2059
1800
|
}
|
|
2060
1801
|
else if (top + tooltipRect.height > viewportHeight - viewportPadding) {
|
|
2061
1802
|
// Tooltip would overflow at the bottom
|
|
@@ -2208,6 +1949,497 @@ const FormHeader = React.forwardRef(({ label, size = "medium", isOptional = fals
|
|
|
2208
1949
|
});
|
|
2209
1950
|
FormHeader.displayName = "FormHeader";
|
|
2210
1951
|
|
|
1952
|
+
const datePickerVariants = cva("relative flex items-center gap-2 border rounded-large transition-all font-display font-size-100 leading-100", {
|
|
1953
|
+
variants: {
|
|
1954
|
+
size: {
|
|
1955
|
+
small: "h-[28px] px-3 text-xs gap-2",
|
|
1956
|
+
medium: "h-[36px] px-4 text-sm gap-2",
|
|
1957
|
+
large: "h-[44px] px-5 text-base gap-3",
|
|
1958
|
+
},
|
|
1959
|
+
validationState: {
|
|
1960
|
+
none: `
|
|
1961
|
+
border-action-outline-neutral-faded
|
|
1962
|
+
hover:border-action-outline-primary-hover
|
|
1963
|
+
focus-within:border-action-outline-primary-hover
|
|
1964
|
+
focus-within:ring-2
|
|
1965
|
+
ring-action-outline-primary-faded-hover`,
|
|
1966
|
+
positive: `
|
|
1967
|
+
border-action-outline-positive-default
|
|
1968
|
+
focus-within:border-action-outline-positive-hover
|
|
1969
|
+
focus-within:ring-2
|
|
1970
|
+
ring-action-outline-positive-faded-hover`,
|
|
1971
|
+
negative: `border-action-outline-negative-default
|
|
1972
|
+
focus-within:border-action-outline-negative-hover
|
|
1973
|
+
focus-within:ring-2
|
|
1974
|
+
ring-action-outline-negative-faded-hover`,
|
|
1975
|
+
},
|
|
1976
|
+
isDisabled: {
|
|
1977
|
+
true: `
|
|
1978
|
+
border-[var(--border-width-thinner)]
|
|
1979
|
+
hover:border-action-outline-neutral-disabled
|
|
1980
|
+
border-action-outline-neutral-disabled
|
|
1981
|
+
bg-surface-fill-neutral-intense cursor-not-allowed opacity-60`,
|
|
1982
|
+
false: "bg-surface-fill-neutral-intense",
|
|
1983
|
+
},
|
|
1984
|
+
},
|
|
1985
|
+
defaultVariants: {
|
|
1986
|
+
size: "medium",
|
|
1987
|
+
validationState: "none",
|
|
1988
|
+
isDisabled: false,
|
|
1989
|
+
},
|
|
1990
|
+
});
|
|
1991
|
+
// Helper functions
|
|
1992
|
+
const parseDate = (date) => {
|
|
1993
|
+
if (!date)
|
|
1994
|
+
return null;
|
|
1995
|
+
if (date instanceof Date)
|
|
1996
|
+
return date;
|
|
1997
|
+
if (typeof date === "string") {
|
|
1998
|
+
const parsed = new Date(date);
|
|
1999
|
+
return isNaN(parsed.getTime()) ? null : parsed;
|
|
2000
|
+
}
|
|
2001
|
+
return null;
|
|
2002
|
+
};
|
|
2003
|
+
const formatDateDefault = (date) => {
|
|
2004
|
+
return date.toLocaleDateString("en-US", {
|
|
2005
|
+
year: "numeric",
|
|
2006
|
+
month: "short",
|
|
2007
|
+
day: "numeric",
|
|
2008
|
+
});
|
|
2009
|
+
};
|
|
2010
|
+
const DatePicker = React.forwardRef(({ className, value: controlledValue, defaultValue, onChange, placeholder = "Select a date", label, helperText, errorText, successText, validationState = "none", isDisabled = false, isRequired = false, isOptional = false, size = "medium", showClearButton = false, onClear, containerClassName, labelClassName, triggerClassName, calendarClassName, minDate, maxDate, formatDate = formatDateDefault, infoHeading, infoDescription, LinkComponent, linkText, linkHref, onLinkClick, ...props }, ref) => {
|
|
2011
|
+
const [uncontrolledValue, setUncontrolledValue] = React.useState(parseDate(defaultValue));
|
|
2012
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
2013
|
+
const datePickerRef = React.useRef(null);
|
|
2014
|
+
const calendarRef = React.useRef(null);
|
|
2015
|
+
const [dropdownPlacement, setDropdownPlacement] = React.useState("bottom");
|
|
2016
|
+
const value = controlledValue !== undefined
|
|
2017
|
+
? parseDate(controlledValue)
|
|
2018
|
+
: uncontrolledValue;
|
|
2019
|
+
const hasValue = value !== null;
|
|
2020
|
+
// Determine which helper text to show
|
|
2021
|
+
const displayHelperText = errorText || successText || helperText;
|
|
2022
|
+
const currentValidationState = errorText
|
|
2023
|
+
? "negative"
|
|
2024
|
+
: successText
|
|
2025
|
+
? "positive"
|
|
2026
|
+
: validationState;
|
|
2027
|
+
const handleOpenChange = (newOpen) => {
|
|
2028
|
+
if (!isDisabled) {
|
|
2029
|
+
setIsOpen(newOpen);
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
2032
|
+
const toggleOpen = () => {
|
|
2033
|
+
handleOpenChange(!isOpen);
|
|
2034
|
+
};
|
|
2035
|
+
const handleCalendarChange = (value, event) => {
|
|
2036
|
+
// react-calendar can return Date, Date[], or null
|
|
2037
|
+
// We only support single date selection, so we take the first date if it's an array
|
|
2038
|
+
if (!value) {
|
|
2039
|
+
if (controlledValue === undefined) {
|
|
2040
|
+
setUncontrolledValue(null);
|
|
2041
|
+
}
|
|
2042
|
+
onChange?.(null);
|
|
2043
|
+
setIsOpen(false);
|
|
2044
|
+
return;
|
|
2045
|
+
}
|
|
2046
|
+
const selectedDate = Array.isArray(value) ? value[0] : value;
|
|
2047
|
+
// Ensure we have a valid Date object
|
|
2048
|
+
if (selectedDate instanceof Date) {
|
|
2049
|
+
if (controlledValue === undefined) {
|
|
2050
|
+
setUncontrolledValue(selectedDate);
|
|
2051
|
+
}
|
|
2052
|
+
onChange?.(selectedDate);
|
|
2053
|
+
setIsOpen(false);
|
|
2054
|
+
}
|
|
2055
|
+
};
|
|
2056
|
+
const handleClear = (e) => {
|
|
2057
|
+
e.stopPropagation();
|
|
2058
|
+
if (onClear) {
|
|
2059
|
+
onClear();
|
|
2060
|
+
}
|
|
2061
|
+
else {
|
|
2062
|
+
if (controlledValue === undefined) {
|
|
2063
|
+
setUncontrolledValue(null);
|
|
2064
|
+
}
|
|
2065
|
+
onChange?.(null);
|
|
2066
|
+
}
|
|
2067
|
+
};
|
|
2068
|
+
const updateDropdownPlacement = React.useCallback(() => {
|
|
2069
|
+
if (typeof window === "undefined")
|
|
2070
|
+
return;
|
|
2071
|
+
const trigger = datePickerRef.current;
|
|
2072
|
+
if (!trigger)
|
|
2073
|
+
return;
|
|
2074
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2075
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom;
|
|
2076
|
+
const spaceAbove = triggerRect.top;
|
|
2077
|
+
const calendarHeight = calendarRef.current
|
|
2078
|
+
? calendarRef.current.offsetHeight
|
|
2079
|
+
: 0;
|
|
2080
|
+
if (calendarHeight === 0) {
|
|
2081
|
+
setDropdownPlacement(spaceBelow >= spaceAbove ? "bottom" : "top");
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
if (spaceBelow >= calendarHeight || spaceBelow >= spaceAbove) {
|
|
2085
|
+
setDropdownPlacement("bottom");
|
|
2086
|
+
}
|
|
2087
|
+
else {
|
|
2088
|
+
setDropdownPlacement("top");
|
|
2089
|
+
}
|
|
2090
|
+
}, []);
|
|
2091
|
+
React.useEffect(() => {
|
|
2092
|
+
if (!isOpen)
|
|
2093
|
+
return;
|
|
2094
|
+
if (typeof window === "undefined")
|
|
2095
|
+
return;
|
|
2096
|
+
let rafId = requestAnimationFrame(updateDropdownPlacement);
|
|
2097
|
+
const handleUpdate = () => updateDropdownPlacement();
|
|
2098
|
+
window.addEventListener("resize", handleUpdate);
|
|
2099
|
+
window.addEventListener("scroll", handleUpdate, true);
|
|
2100
|
+
return () => {
|
|
2101
|
+
cancelAnimationFrame(rafId);
|
|
2102
|
+
window.removeEventListener("resize", handleUpdate);
|
|
2103
|
+
window.removeEventListener("scroll", handleUpdate, true);
|
|
2104
|
+
};
|
|
2105
|
+
}, [isOpen, updateDropdownPlacement]);
|
|
2106
|
+
React.useEffect(() => {
|
|
2107
|
+
if (isOpen) {
|
|
2108
|
+
updateDropdownPlacement();
|
|
2109
|
+
}
|
|
2110
|
+
}, [isOpen, updateDropdownPlacement]);
|
|
2111
|
+
// Close calendar when clicking outside
|
|
2112
|
+
React.useEffect(() => {
|
|
2113
|
+
const handleClickOutside = (event) => {
|
|
2114
|
+
if (datePickerRef.current &&
|
|
2115
|
+
!datePickerRef.current.contains(event.target)) {
|
|
2116
|
+
handleOpenChange(false);
|
|
2117
|
+
}
|
|
2118
|
+
};
|
|
2119
|
+
if (isOpen) {
|
|
2120
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2121
|
+
return () => {
|
|
2122
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
}, [isOpen]);
|
|
2126
|
+
// Close on escape key
|
|
2127
|
+
React.useEffect(() => {
|
|
2128
|
+
const handleEscape = (event) => {
|
|
2129
|
+
if (event.key === "Escape") {
|
|
2130
|
+
handleOpenChange(false);
|
|
2131
|
+
}
|
|
2132
|
+
};
|
|
2133
|
+
if (isOpen) {
|
|
2134
|
+
document.addEventListener("keydown", handleEscape);
|
|
2135
|
+
return () => {
|
|
2136
|
+
document.removeEventListener("keydown", handleEscape);
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
}, [isOpen]);
|
|
2140
|
+
const minDateParsed = parseDate(minDate);
|
|
2141
|
+
const maxDateParsed = parseDate(maxDate);
|
|
2142
|
+
const sizeConfig = {
|
|
2143
|
+
small: {
|
|
2144
|
+
gap: "gap-2",
|
|
2145
|
+
},
|
|
2146
|
+
medium: {
|
|
2147
|
+
gap: "gap-2",
|
|
2148
|
+
},
|
|
2149
|
+
large: {
|
|
2150
|
+
gap: "gap-3",
|
|
2151
|
+
},
|
|
2152
|
+
};
|
|
2153
|
+
return (jsxs("div", { className: cn("w-full flex flex-col", sizeConfig[size].gap, containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, LinkComponent: LinkComponent, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { ref: datePickerRef, className: cn(datePickerVariants({
|
|
2154
|
+
size,
|
|
2155
|
+
validationState: currentValidationState,
|
|
2156
|
+
isDisabled,
|
|
2157
|
+
}), "relative w-full cursor-pointer", className), onClick: !isDisabled ? toggleOpen : undefined, role: "button", "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-disabled": isDisabled, ...props, children: [jsx(Calendar, { className: cn("shrink-0 w-4 h-4", isDisabled
|
|
2158
|
+
? "text-surface-ink-neutral-disabled"
|
|
2159
|
+
: currentValidationState === "positive"
|
|
2160
|
+
? "text-feedback-ink-positive-intense"
|
|
2161
|
+
: currentValidationState === "negative"
|
|
2162
|
+
? "text-feedback-ink-negative-subtle"
|
|
2163
|
+
: "text-surface-ink-neutral-muted") }), jsx("span", { className: cn("flex-1 text-left truncate", !hasValue && "text-surface-ink-neutral-muted", isDisabled && "text-surface-ink-neutral-disabled"), children: hasValue && value ? formatDate(value) : placeholder }), showClearButton && hasValue && !isDisabled && (jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), isOpen && !isDisabled && (jsx("div", { ref: calendarRef, className: cn("absolute z-50 left-0 bg-surface-fill-neutral-intense rounded-large shadow-lg p-4", dropdownPlacement === "bottom"
|
|
2164
|
+
? "top-full mt-1"
|
|
2165
|
+
: "bottom-full mb-1", calendarClassName), onClick: (e) => e.stopPropagation(), children: jsx("div", { className: "react-calendar-wrapper w-fit", children: jsx(Calendar$1, { onChange: handleCalendarChange, value: value ?? null, minDate: minDateParsed ?? undefined, maxDate: maxDateParsed ?? undefined, locale: "en-US", formatShortWeekday: (locale, date) => {
|
|
2166
|
+
const weekdayNames = [
|
|
2167
|
+
"Su",
|
|
2168
|
+
"Mo",
|
|
2169
|
+
"Tu",
|
|
2170
|
+
"We",
|
|
2171
|
+
"Th",
|
|
2172
|
+
"Fr",
|
|
2173
|
+
"Sa",
|
|
2174
|
+
];
|
|
2175
|
+
return weekdayNames[date.getDay()];
|
|
2176
|
+
} }) }) }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
|
|
2177
|
+
? "default"
|
|
2178
|
+
: currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
|
|
2179
|
+
});
|
|
2180
|
+
DatePicker.displayName = "DatePicker";
|
|
2181
|
+
|
|
2182
|
+
const dividerVariants = cva("", {
|
|
2183
|
+
variants: {
|
|
2184
|
+
orientation: {
|
|
2185
|
+
horizontal: "w-full",
|
|
2186
|
+
vertical: "h-full",
|
|
2187
|
+
},
|
|
2188
|
+
thickness: {
|
|
2189
|
+
thinner: "",
|
|
2190
|
+
thin: "",
|
|
2191
|
+
thick: "",
|
|
2192
|
+
thicker: "",
|
|
2193
|
+
},
|
|
2194
|
+
lineStyle: {
|
|
2195
|
+
solid: "border-solid",
|
|
2196
|
+
dashed: "border-dashed",
|
|
2197
|
+
},
|
|
2198
|
+
variant: {
|
|
2199
|
+
normal: "",
|
|
2200
|
+
subtle: "",
|
|
2201
|
+
muted: "",
|
|
2202
|
+
},
|
|
2203
|
+
},
|
|
2204
|
+
compoundVariants: [
|
|
2205
|
+
// Horizontal orientation with thickness
|
|
2206
|
+
{
|
|
2207
|
+
orientation: "horizontal",
|
|
2208
|
+
thickness: "thinner",
|
|
2209
|
+
class: "border-t-[0.5px]",
|
|
2210
|
+
},
|
|
2211
|
+
{
|
|
2212
|
+
orientation: "horizontal",
|
|
2213
|
+
thickness: "thin",
|
|
2214
|
+
class: "border-t-[1px]",
|
|
2215
|
+
},
|
|
2216
|
+
{
|
|
2217
|
+
orientation: "horizontal",
|
|
2218
|
+
thickness: "thick",
|
|
2219
|
+
class: "border-t-[2px]",
|
|
2220
|
+
},
|
|
2221
|
+
{
|
|
2222
|
+
orientation: "horizontal",
|
|
2223
|
+
thickness: "thicker",
|
|
2224
|
+
class: "border-t-[3px]",
|
|
2225
|
+
},
|
|
2226
|
+
// Vertical orientation with thickness
|
|
2227
|
+
{
|
|
2228
|
+
orientation: "vertical",
|
|
2229
|
+
thickness: "thinner",
|
|
2230
|
+
class: "border-l-[0.5px]",
|
|
2231
|
+
},
|
|
2232
|
+
{
|
|
2233
|
+
orientation: "vertical",
|
|
2234
|
+
thickness: "thin",
|
|
2235
|
+
class: "border-l-[1px]",
|
|
2236
|
+
},
|
|
2237
|
+
{
|
|
2238
|
+
orientation: "vertical",
|
|
2239
|
+
thickness: "thick",
|
|
2240
|
+
class: "border-l-[2px]",
|
|
2241
|
+
},
|
|
2242
|
+
{
|
|
2243
|
+
orientation: "vertical",
|
|
2244
|
+
thickness: "thicker",
|
|
2245
|
+
class: "border-l-[3px]",
|
|
2246
|
+
},
|
|
2247
|
+
// Normal variant colors
|
|
2248
|
+
{
|
|
2249
|
+
variant: "normal",
|
|
2250
|
+
class: "border-surface-outline-neutral-normal",
|
|
2251
|
+
},
|
|
2252
|
+
// Subtle variant colors
|
|
2253
|
+
{
|
|
2254
|
+
variant: "subtle",
|
|
2255
|
+
class: "border-surface-outline-neutral-subtle",
|
|
2256
|
+
},
|
|
2257
|
+
// Muted variant colors
|
|
2258
|
+
{
|
|
2259
|
+
variant: "muted",
|
|
2260
|
+
class: "border-surface-outline-neutral-muted",
|
|
2261
|
+
},
|
|
2262
|
+
],
|
|
2263
|
+
defaultVariants: {
|
|
2264
|
+
orientation: "horizontal",
|
|
2265
|
+
thickness: "thin",
|
|
2266
|
+
lineStyle: "solid",
|
|
2267
|
+
variant: "normal",
|
|
2268
|
+
},
|
|
2269
|
+
});
|
|
2270
|
+
const Divider = React.forwardRef(({ className, orientation = "horizontal", thickness = "thin", lineStyle = "solid", variant = "normal", ...props }, ref) => {
|
|
2271
|
+
return (jsx("div", { ref: ref, role: "separator", "aria-orientation": orientation, className: cn(dividerVariants({ orientation, thickness, lineStyle, variant }), className), ...props }));
|
|
2272
|
+
});
|
|
2273
|
+
Divider.displayName = "Divider";
|
|
2274
|
+
|
|
2275
|
+
const listItemVariants = cva("flex items-start gap-3 p-3 rounded-medium transition-colors cursor-pointer", {
|
|
2276
|
+
variants: {
|
|
2277
|
+
variant: {
|
|
2278
|
+
default: `hover:bg-action-fill-neutral-faded
|
|
2279
|
+
focus:bg-action-fill-neutral-faded
|
|
2280
|
+
focus:ring-2
|
|
2281
|
+
ring-action-outline-primary-faded-hover
|
|
2282
|
+
border border-transparent
|
|
2283
|
+
`,
|
|
2284
|
+
bordered: "border border-action-outline-primary-faded hover:bg-surface-fill-primary-subtle",
|
|
2285
|
+
primary: `hover:bg-action-fill-neutral-faded
|
|
2286
|
+
focus:bg-action-fill-neutral-faded
|
|
2287
|
+
focus:ring-2
|
|
2288
|
+
ring-action-outline-primary-faded-hover
|
|
2289
|
+
border border-transparent
|
|
2290
|
+
`,
|
|
2291
|
+
negative: `hover:bg-action-fill-negative-faded
|
|
2292
|
+
focus:bg-action-fill-negative-faded
|
|
2293
|
+
focus:ring-2 ring-action-outline-negative-faded-hover
|
|
2294
|
+
border border-transparent
|
|
2295
|
+
`,
|
|
2296
|
+
},
|
|
2297
|
+
isDisabled: {
|
|
2298
|
+
true: "cursor-not-allowed opacity-60",
|
|
2299
|
+
false: "",
|
|
2300
|
+
},
|
|
2301
|
+
isSelected: {
|
|
2302
|
+
true: "bg-action-fill-primary-faded border-action-outline-primary-faded",
|
|
2303
|
+
false: "",
|
|
2304
|
+
},
|
|
2305
|
+
},
|
|
2306
|
+
defaultVariants: {
|
|
2307
|
+
variant: "default",
|
|
2308
|
+
isDisabled: false,
|
|
2309
|
+
isSelected: false,
|
|
2310
|
+
},
|
|
2311
|
+
});
|
|
2312
|
+
const ChevronRightIcon = ({ className }) => (jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: className, children: jsx("path", { d: "M7.5 15L12.5 10L7.5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
2313
|
+
const ListItem = React.forwardRef(({ className, type = "single", leadingIcon, title, description, trailingIcon, showChevron = true, variant = "default", isDisabled = false, isSelected = false, onSelectionChange, checkboxSize = "small", containerClassName, contentClassName, onClick, ...props }, ref) => {
|
|
2314
|
+
const [internalSelected, setInternalSelected] = React.useState(isSelected);
|
|
2315
|
+
// Sync internal state with prop
|
|
2316
|
+
React.useEffect(() => {
|
|
2317
|
+
setInternalSelected(isSelected);
|
|
2318
|
+
}, [isSelected]);
|
|
2319
|
+
const handleClick = (e) => {
|
|
2320
|
+
if (isDisabled)
|
|
2321
|
+
return;
|
|
2322
|
+
if (type === "multiple") {
|
|
2323
|
+
const newSelected = !internalSelected;
|
|
2324
|
+
setInternalSelected(newSelected);
|
|
2325
|
+
onSelectionChange?.(newSelected);
|
|
2326
|
+
}
|
|
2327
|
+
onClick?.(e);
|
|
2328
|
+
};
|
|
2329
|
+
const handleCheckboxChange = (e) => {
|
|
2330
|
+
e.stopPropagation();
|
|
2331
|
+
if (isDisabled)
|
|
2332
|
+
return;
|
|
2333
|
+
const newSelected = e.target.checked;
|
|
2334
|
+
setInternalSelected(newSelected);
|
|
2335
|
+
onSelectionChange?.(newSelected);
|
|
2336
|
+
};
|
|
2337
|
+
return (jsxs("div", { ref: ref, className: cn(listItemVariants({
|
|
2338
|
+
variant,
|
|
2339
|
+
isDisabled,
|
|
2340
|
+
isSelected: type === "multiple" ? internalSelected : false,
|
|
2341
|
+
}), containerClassName), onClick: handleClick, role: type === "multiple" ? "checkbox" : "button", "aria-checked": type === "multiple" ? internalSelected : undefined, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, ...props, children: [type === "multiple" && (jsx(Checkbox, { checked: internalSelected, onChange: handleCheckboxChange, isDisabled: isDisabled, size: checkboxSize, className: "shrink-0 mt-0.5" })), leadingIcon && (jsx("div", { className: cn(`shrink-0 flex items-center justify-center mt-0.5`, variant === "primary"
|
|
2342
|
+
? "text-action-ink-primary-normal"
|
|
2343
|
+
: variant === "negative"
|
|
2344
|
+
? "text-action-ink-negative-normal"
|
|
2345
|
+
: "text-action-ink-neutral-subtle", isDisabled && "text-surface-ink-neutral-disabled"), children: leadingIcon })), jsxs("div", { className: cn("flex-1 min-w-0 flex flex-col justify-center", contentClassName), children: [jsx("div", { className: cn("text-body-medium-regular truncate", variant === "primary"
|
|
2346
|
+
? "text-action-ink-primary-normal"
|
|
2347
|
+
: variant === "negative"
|
|
2348
|
+
? "text-action-ink-negative-normal"
|
|
2349
|
+
: "text-action-ink-neutral-normal", isDisabled && "text-surface-ink-neutral-disabled"), children: title }), description && (jsx("div", { className: cn("text-body-small-regular text-surface-ink-neutral-muted mt-0.5 line-clamp-2", isDisabled && "text-surface-ink-neutral-disabled"), children: description }))] }), (trailingIcon || showChevron) && (jsx("div", { className: "shrink-0 self-center text-action-ink-neutral-subtle", children: trailingIcon || jsx(ChevronRightIcon, {}) }))] }));
|
|
2350
|
+
});
|
|
2351
|
+
ListItem.displayName = "ListItem";
|
|
2352
|
+
|
|
2353
|
+
const DropdownMenu = React.forwardRef(({ items = [], customContent, sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, showChevron = false, emptyIcon, disableFooter = false, showFooter, footerLayout = "horizontal", onClose, focusedIndex = -1, className, width = "auto", }, ref) => {
|
|
2354
|
+
const renderContent = () => {
|
|
2355
|
+
if (isLoading) {
|
|
2356
|
+
return (jsx("div", { className: "flex flex-col items-center justify-center py-12 px-6", children: jsx(Loader2, { className: "w-12 h-12 text-action-ink-primary-normal mb-4 animate-spin" }) }));
|
|
2357
|
+
}
|
|
2358
|
+
if (customContent) {
|
|
2359
|
+
return (jsxs("div", { className: "py-3 px-3 max-h-[400px] overflow-y-auto", children: [sectionHeading && (jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-body-small-medium text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsx("div", { className: "px-1", children: customContent })] }));
|
|
2360
|
+
}
|
|
2361
|
+
if (isEmpty || items.length === 0) {
|
|
2362
|
+
return (jsxs("div", { className: "flex flex-col items-center justify-center py-8 px-6 text-center", children: [emptyIcon || (jsx(Search, { className: "w-12 h-12 text-surface-ink-neutral-muted mb-4" })), jsx(Text, { as: "h3", variant: "body", size: "small", weight: "semibold", className: "text-surface-ink-neutral-normal mb-2", children: emptyTitle }), jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", className: "text-surface-ink-neutral-muted mb-3", children: emptyDescription }), emptyLinkText && (jsx(Link, { type: "anchor", color: "primary", size: "small", onClick: onEmptyLinkClick, children: emptyLinkText }))] }));
|
|
2363
|
+
}
|
|
2364
|
+
return (jsxs("div", { className: "py-3 px-3 max-h-[400px] overflow-y-auto", children: [sectionHeading && (jsx(Text, { as: "div", variant: "body", size: "small", weight: "medium", className: "text-surface-ink-neutral-muted px-3 py-2 mb-1", children: sectionHeading })), jsx("div", { className: "flex flex-col gap-1", children: items.map((item, index) => (jsx(ListItem, { title: item.label, description: item.description, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon, showChevron: showChevron, isDisabled: item.isDisabled, isSelected: index === focusedIndex, variant: item.variant, onClick: () => {
|
|
2365
|
+
item.onClick?.();
|
|
2366
|
+
onClose?.();
|
|
2367
|
+
}, containerClassName: cn(index === focusedIndex && "bg-action-fill-primary-faded") }, item.value))) })] }));
|
|
2368
|
+
};
|
|
2369
|
+
const widthClass = width === "full" ? "w-full" : width === "auto" ? "w-auto" : "";
|
|
2370
|
+
const footerVisible = showFooter ?? !disableFooter;
|
|
2371
|
+
return (jsxs("div", { ref: ref, className: cn("bg-white rounded-large overflow-hidden", widthClass, className), style: {
|
|
2372
|
+
boxShadow: "0 1px 2px rgba(25, 25, 30, 0.1), 0 2px 6px rgba(25, 25, 30, 0.06)",
|
|
2373
|
+
...(width !== "full" && width !== "auto" ? { width } : {}),
|
|
2374
|
+
}, children: [renderContent(), footerVisible && (jsxs("div", { className: "flex flex-col", children: [jsx(Divider, { thickness: "thin", variant: "muted" }), jsxs("div", { className: cn("flex gap-3 p-4", footerLayout === "vertical"
|
|
2375
|
+
? "flex-col"
|
|
2376
|
+
: "items-center flex-row"), children: [jsx(Button, { variant: "secondary", color: "primary", size: "medium", isFullWidth: true, onClick: onSecondaryClick, children: secondaryButtonText }), jsx(Button, { variant: "primary", color: "primary", size: "medium", isFullWidth: true, onClick: onPrimaryClick, children: primaryButtonText })] })] }))] }));
|
|
2377
|
+
});
|
|
2378
|
+
DropdownMenu.displayName = "DropdownMenu";
|
|
2379
|
+
|
|
2380
|
+
const dropdownVariants = cva("bg-surface-fill-primary-normal border border-surface-outline-neutral-subtle rounded-large", {
|
|
2381
|
+
variants: {
|
|
2382
|
+
size: {
|
|
2383
|
+
small: "w-64",
|
|
2384
|
+
medium: "w-80",
|
|
2385
|
+
large: "w-96",
|
|
2386
|
+
},
|
|
2387
|
+
},
|
|
2388
|
+
defaultVariants: {
|
|
2389
|
+
size: "medium",
|
|
2390
|
+
},
|
|
2391
|
+
});
|
|
2392
|
+
const Dropdown = React.forwardRef(({ className, trigger, items = [], customContent, sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, size = "medium", open: controlledOpen, defaultOpen = false, onOpenChange, containerClassName, menuClassName, showChevron = false, emptyIcon, disableFooter = false, showFooter, ...props }, ref) => {
|
|
2393
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
2394
|
+
const isOpen = controlledOpen !== undefined ? controlledOpen : uncontrolledOpen;
|
|
2395
|
+
const dropdownRef = React.useRef(null);
|
|
2396
|
+
const handleOpenChange = (newOpen) => {
|
|
2397
|
+
if (controlledOpen === undefined) {
|
|
2398
|
+
setUncontrolledOpen(newOpen);
|
|
2399
|
+
}
|
|
2400
|
+
onOpenChange?.(newOpen);
|
|
2401
|
+
};
|
|
2402
|
+
const toggleOpen = () => {
|
|
2403
|
+
handleOpenChange(!isOpen);
|
|
2404
|
+
};
|
|
2405
|
+
// Close dropdown when clicking outside
|
|
2406
|
+
React.useEffect(() => {
|
|
2407
|
+
const handleClickOutside = (event) => {
|
|
2408
|
+
if (dropdownRef.current &&
|
|
2409
|
+
!dropdownRef.current.contains(event.target)) {
|
|
2410
|
+
handleOpenChange(false);
|
|
2411
|
+
}
|
|
2412
|
+
};
|
|
2413
|
+
if (isOpen) {
|
|
2414
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2415
|
+
return () => {
|
|
2416
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
}, [isOpen]);
|
|
2420
|
+
// Close on escape key
|
|
2421
|
+
React.useEffect(() => {
|
|
2422
|
+
const handleEscape = (event) => {
|
|
2423
|
+
if (event.key === "Escape") {
|
|
2424
|
+
handleOpenChange(false);
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
if (isOpen) {
|
|
2428
|
+
document.addEventListener("keydown", handleEscape);
|
|
2429
|
+
return () => {
|
|
2430
|
+
document.removeEventListener("keydown", handleEscape);
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
}, [isOpen]);
|
|
2434
|
+
const sizeMap = {
|
|
2435
|
+
small: "w-64",
|
|
2436
|
+
medium: "w-80",
|
|
2437
|
+
large: "w-96",
|
|
2438
|
+
};
|
|
2439
|
+
return (jsxs("div", { ref: dropdownRef, className: cn("relative inline-block", containerClassName), ...props, children: [trigger && (jsx("div", { onClick: toggleOpen, className: "cursor-pointer", children: trigger })), isOpen && (jsx(DropdownMenu, { ref: ref, items: items, customContent: customContent, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: isEmpty, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, showFooter: showFooter, onClose: () => handleOpenChange(false), className: cn("absolute z-50 mt-2", menuClassName, className), width: sizeMap[size] }))] }));
|
|
2440
|
+
});
|
|
2441
|
+
Dropdown.displayName = "Dropdown";
|
|
2442
|
+
|
|
2211
2443
|
const Modal = React.forwardRef(({ isOpen, onClose, title, description, footer, children, size = "medium", showCloseButton = true, closeOnOverlayClick = true, closeOnEscape = true, className, contentClassName, headerClassName, bodyClassName, footerClassName, overlayClassName, ariaLabel, ariaDescribedBy, }, ref) => {
|
|
2212
2444
|
const modalRef = React.useRef(null);
|
|
2213
2445
|
const contentRef = ref || modalRef;
|
|
@@ -3713,5 +3945,5 @@ const TextArea = React.forwardRef(({ label, helperText, errorText, successText,
|
|
|
3713
3945
|
});
|
|
3714
3946
|
TextArea.displayName = "TextArea";
|
|
3715
3947
|
|
|
3716
|
-
export { Alert, Avatar, AvatarCell, Badge, Button, ButtonGroup, Checkbox, Counter, Divider, Dropdown, DropdownMenu, FormFooter, FormHeader, Icon, IconButton, IconCell, Link, ListItem, Modal, NumberCell, Pagination, Radio, SearchableDropdown, Select, Skeleton, SlotCell, SpacerCell, Switch, TabItem, Table, TableDetailPanel, Tabs, Text, TextArea, TextField, Tooltip, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, checkboxVariants, cn, counterVariants, dropdownVariants, getAvailableIcons, hasIcon, iconButtonVariants, iconRegistry, linkVariants, listItemVariants, paginationVariants, radioVariants, selectVariants, switchVariants, tableCellVariants, tableHeaderVariants, tableVariants, textAreaVariants, textFieldVariants, tooltipVariants };
|
|
3948
|
+
export { Alert, Avatar, AvatarCell, Badge, Button, ButtonGroup, Checkbox, Counter, DatePicker, Divider, Dropdown, DropdownMenu, FormFooter, FormHeader, Icon, IconButton, IconCell, Link, ListItem, Modal, NumberCell, Pagination, Radio, SearchableDropdown, Select, Skeleton, SlotCell, SpacerCell, Switch, TabItem, Table, TableDetailPanel, Tabs, Text, TextArea, TextField, Tooltip, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, checkboxVariants, cn, counterVariants, datePickerVariants, dropdownVariants, getAvailableIcons, hasIcon, iconButtonVariants, iconRegistry, linkVariants, listItemVariants, paginationVariants, radioVariants, selectVariants, switchVariants, tableCellVariants, tableHeaderVariants, tableVariants, textAreaVariants, textFieldVariants, tooltipVariants };
|
|
3717
3949
|
//# sourceMappingURL=index.esm.js.map
|