react-material-expressive 1.0.0 → 1.1.0
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/CHANGELOG.md +54 -1
- package/README.md +28 -23
- package/dist/index.cjs +1241 -491
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -9
- package/dist/index.d.ts +110 -9
- package/dist/index.js +1240 -492
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme.css +5 -0
- package/docs/components/Combobox.md +119 -0
- package/docs/components/DatePicker.md +14 -2
- package/docs/components/Dropdown.md +4 -0
- package/docs/components/Layers.md +3 -0
- package/docs/components/Menu.md +4 -0
- package/docs/components/NavigationRail.md +3 -0
- package/docs/components/OverflowMenu.md +5 -1
- package/docs/components/Search.md +9 -1
- package/docs/components/SplitButton.md +3 -1
- package/docs/components/TextElement.md +15 -0
- package/llms.txt +64 -59
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -563,7 +563,8 @@ function useOutsideClose(ref, onClose, enabled = true) {
|
|
|
563
563
|
const target = event.target;
|
|
564
564
|
if (!element || !(target instanceof Node)) return;
|
|
565
565
|
if (element.contains(target)) return;
|
|
566
|
-
if (target instanceof Element && target.closest('[role="menu"]'))
|
|
566
|
+
if (target instanceof Element && target.closest('[role="menu"],[role="listbox"]'))
|
|
567
|
+
return;
|
|
567
568
|
onClose();
|
|
568
569
|
};
|
|
569
570
|
document.addEventListener("pointerdown", handler);
|
|
@@ -798,6 +799,83 @@ function IconButton({
|
|
|
798
799
|
}
|
|
799
800
|
);
|
|
800
801
|
}
|
|
802
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? react.useEffect : react.useLayoutEffect;
|
|
803
|
+
|
|
804
|
+
// src/components/_usePopoverPosition.ts
|
|
805
|
+
var MARGIN = 8;
|
|
806
|
+
var FALLBACK_WIDTH = 224;
|
|
807
|
+
function usePopoverPosition(anchor, floating, open, options = {}) {
|
|
808
|
+
const { gap = 0, matchWidth = false, placement = "bottom-start" } = options;
|
|
809
|
+
const [pos, setPos] = react.useState({
|
|
810
|
+
flippedVertically: false,
|
|
811
|
+
left: 0,
|
|
812
|
+
top: 0
|
|
813
|
+
});
|
|
814
|
+
useIsomorphicLayoutEffect(() => {
|
|
815
|
+
if (!open) return;
|
|
816
|
+
const compute = () => {
|
|
817
|
+
const a = anchor.current?.getBoundingClientRect();
|
|
818
|
+
if (!a) return;
|
|
819
|
+
const f = floating.current?.getBoundingClientRect();
|
|
820
|
+
const width = matchWidth ? a.width : f?.width || FALLBACK_WIDTH;
|
|
821
|
+
const height = f?.height || 0;
|
|
822
|
+
const vw = window.innerWidth;
|
|
823
|
+
const vh = window.innerHeight;
|
|
824
|
+
const dash = placement.indexOf("-");
|
|
825
|
+
const side = placement.slice(0, dash);
|
|
826
|
+
const align = placement.slice(dash + 1);
|
|
827
|
+
let left;
|
|
828
|
+
let top;
|
|
829
|
+
let flippedVertically = false;
|
|
830
|
+
if (side === "right") {
|
|
831
|
+
left = a.right + gap;
|
|
832
|
+
if (left + width > vw - MARGIN) {
|
|
833
|
+
const flipped = a.left - width - gap;
|
|
834
|
+
left = flipped >= MARGIN ? flipped : Math.max(MARGIN, vw - MARGIN - width);
|
|
835
|
+
}
|
|
836
|
+
top = a.top;
|
|
837
|
+
if (top + height > vh - MARGIN) {
|
|
838
|
+
top = Math.max(MARGIN, vh - MARGIN - height);
|
|
839
|
+
}
|
|
840
|
+
} else {
|
|
841
|
+
left = align === "end" ? a.right - width : a.left;
|
|
842
|
+
if (left + width > vw - MARGIN) left = vw - MARGIN - width;
|
|
843
|
+
if (left < MARGIN) left = MARGIN;
|
|
844
|
+
const below = a.bottom + gap;
|
|
845
|
+
const above = a.top - height - gap;
|
|
846
|
+
const roomBelow = vh - MARGIN - a.bottom;
|
|
847
|
+
const roomAbove = a.top - MARGIN;
|
|
848
|
+
if (side === "bottom") {
|
|
849
|
+
if (height > roomBelow && roomAbove > roomBelow) {
|
|
850
|
+
top = Math.max(MARGIN, above);
|
|
851
|
+
flippedVertically = true;
|
|
852
|
+
} else {
|
|
853
|
+
top = below;
|
|
854
|
+
}
|
|
855
|
+
} else if (height > roomAbove && roomBelow > roomAbove) {
|
|
856
|
+
top = below;
|
|
857
|
+
flippedVertically = true;
|
|
858
|
+
} else {
|
|
859
|
+
top = Math.max(MARGIN, above);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
setPos({
|
|
863
|
+
flippedVertically,
|
|
864
|
+
left,
|
|
865
|
+
top,
|
|
866
|
+
width: matchWidth ? a.width : void 0
|
|
867
|
+
});
|
|
868
|
+
};
|
|
869
|
+
compute();
|
|
870
|
+
window.addEventListener("scroll", compute, true);
|
|
871
|
+
window.addEventListener("resize", compute);
|
|
872
|
+
return () => {
|
|
873
|
+
window.removeEventListener("scroll", compute, true);
|
|
874
|
+
window.removeEventListener("resize", compute);
|
|
875
|
+
};
|
|
876
|
+
}, [anchor, floating, open, gap, matchWidth, placement]);
|
|
877
|
+
return pos;
|
|
878
|
+
}
|
|
801
879
|
var MENU_NOOP = () => {
|
|
802
880
|
};
|
|
803
881
|
var MenuContext = react.createContext({
|
|
@@ -920,41 +998,6 @@ function MenuLabel({ children, className, leftElement }) {
|
|
|
920
998
|
}
|
|
921
999
|
);
|
|
922
1000
|
}
|
|
923
|
-
var useIsomorphicLayoutEffect = typeof window === "undefined" ? react.useEffect : react.useLayoutEffect;
|
|
924
|
-
|
|
925
|
-
// src/components/menu/_useSubmenu.ts
|
|
926
|
-
var MARGIN = 8;
|
|
927
|
-
function useSubmenuPosition(anchor, floating, open) {
|
|
928
|
-
const [pos, setPos] = react.useState({ left: 0, top: 0 });
|
|
929
|
-
useIsomorphicLayoutEffect(() => {
|
|
930
|
-
if (!open) return;
|
|
931
|
-
const compute = () => {
|
|
932
|
-
const a = anchor.current?.getBoundingClientRect();
|
|
933
|
-
if (!a) return;
|
|
934
|
-
const f = floating.current?.getBoundingClientRect();
|
|
935
|
-
const width = f?.width || 224;
|
|
936
|
-
const height = f?.height || 0;
|
|
937
|
-
let left = a.right;
|
|
938
|
-
if (left + width > window.innerWidth - MARGIN) {
|
|
939
|
-
const flipped = a.left - width;
|
|
940
|
-
left = flipped >= MARGIN ? flipped : Math.max(MARGIN, window.innerWidth - MARGIN - width);
|
|
941
|
-
}
|
|
942
|
-
let top = a.top;
|
|
943
|
-
if (top + height > window.innerHeight - MARGIN) {
|
|
944
|
-
top = Math.max(MARGIN, window.innerHeight - MARGIN - height);
|
|
945
|
-
}
|
|
946
|
-
setPos({ left, top });
|
|
947
|
-
};
|
|
948
|
-
compute();
|
|
949
|
-
window.addEventListener("scroll", compute, true);
|
|
950
|
-
window.addEventListener("resize", compute);
|
|
951
|
-
return () => {
|
|
952
|
-
window.removeEventListener("scroll", compute, true);
|
|
953
|
-
window.removeEventListener("resize", compute);
|
|
954
|
-
};
|
|
955
|
-
}, [anchor, floating, open]);
|
|
956
|
-
return pos;
|
|
957
|
-
}
|
|
958
1001
|
var HOVER_OPEN_MS = 120;
|
|
959
1002
|
var HOVER_CLOSE_MS = 220;
|
|
960
1003
|
function ChevronRight() {
|
|
@@ -984,7 +1027,9 @@ function MenuSub({
|
|
|
984
1027
|
const trigger = react.useRef(null);
|
|
985
1028
|
const floating = react.useRef(null);
|
|
986
1029
|
const timer = react.useRef(void 0);
|
|
987
|
-
const pos =
|
|
1030
|
+
const pos = usePopoverPosition(trigger, floating, open, {
|
|
1031
|
+
placement: "right-start"
|
|
1032
|
+
});
|
|
988
1033
|
const clear = () => timer.current && clearTimeout(timer.current);
|
|
989
1034
|
const hoverOpen = () => {
|
|
990
1035
|
clear();
|
|
@@ -1065,7 +1110,7 @@ function MenuSub({
|
|
|
1065
1110
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1066
1111
|
"div",
|
|
1067
1112
|
{
|
|
1068
|
-
className: "fixed z-
|
|
1113
|
+
className: "fixed z-[var(--md-sys-z-menu)]",
|
|
1069
1114
|
onMouseEnter: clear,
|
|
1070
1115
|
onMouseLeave: hoverClose,
|
|
1071
1116
|
ref: floating,
|
|
@@ -1180,7 +1225,7 @@ function Menu({
|
|
|
1180
1225
|
// outline-none: the surface is focusable (tabIndex -1) so a
|
|
1181
1226
|
// root menu can focus it on open without highlighting any
|
|
1182
1227
|
// item — it must never show a focus ring of its own.
|
|
1183
|
-
"z-
|
|
1228
|
+
"z-[var(--md-sys-z-menu)] flex w-max min-w-[112px] max-w-[280px] flex-col outline-none [--menu-clip-bleed:-24px]",
|
|
1184
1229
|
grouped ? (
|
|
1185
1230
|
// Transparent stack: each Menu.Group is its own
|
|
1186
1231
|
// surface, separated by a 2dp gap. overflow-visible
|
|
@@ -1288,8 +1333,13 @@ function SplitButton({
|
|
|
1288
1333
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
1289
1334
|
const wrapper = react.useRef(null);
|
|
1290
1335
|
const trailing = react.useRef(null);
|
|
1336
|
+
const floating = react.useRef(null);
|
|
1291
1337
|
const wasOpen = react.useRef(false);
|
|
1292
1338
|
const { exiting, mounted } = useDismissable(isOpen, 150);
|
|
1339
|
+
const pos = usePopoverPosition(wrapper, floating, mounted, {
|
|
1340
|
+
gap: 8,
|
|
1341
|
+
placement: "bottom-end"
|
|
1342
|
+
});
|
|
1293
1343
|
const config = SIZES4[size];
|
|
1294
1344
|
const corners = (classes) => disabled ? classes.replace(/ (?:hover|focus-visible|active):\S+/g, "") : classes;
|
|
1295
1345
|
useOutsideClose(wrapper, () => setIsOpen(false), isOpen);
|
|
@@ -1363,15 +1413,27 @@ function SplitButton({
|
|
|
1363
1413
|
)
|
|
1364
1414
|
}
|
|
1365
1415
|
),
|
|
1366
|
-
mounted
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1416
|
+
mounted && typeof document !== "undefined" ? reactDom.createPortal(
|
|
1417
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1418
|
+
"div",
|
|
1419
|
+
{
|
|
1420
|
+
className: "fixed z-[var(--md-sys-z-menu)]",
|
|
1421
|
+
ref: floating,
|
|
1422
|
+
style: { left: pos.left, top: pos.top },
|
|
1423
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1424
|
+
Menu,
|
|
1425
|
+
{
|
|
1426
|
+
className: menuClassName,
|
|
1427
|
+
exiting,
|
|
1428
|
+
onClose: () => setIsOpen(false),
|
|
1429
|
+
up: pos.flippedVertically,
|
|
1430
|
+
children: menu
|
|
1431
|
+
}
|
|
1432
|
+
)
|
|
1433
|
+
}
|
|
1434
|
+
),
|
|
1435
|
+
document.body
|
|
1436
|
+
) : null
|
|
1375
1437
|
]
|
|
1376
1438
|
}
|
|
1377
1439
|
);
|
|
@@ -1550,37 +1612,981 @@ function Chips({
|
|
|
1550
1612
|
children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { selected })
|
|
1551
1613
|
}
|
|
1552
1614
|
),
|
|
1553
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1554
|
-
"span",
|
|
1615
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1616
|
+
"span",
|
|
1617
|
+
{
|
|
1618
|
+
className: cn(
|
|
1619
|
+
"absolute inset-0 flex items-center justify-center",
|
|
1620
|
+
selected ? "ease-md-linear opacity-0 transition-opacity duration-[50ms]" : "ease-legacy opacity-100 transition-opacity delay-[50ms] duration-150",
|
|
1621
|
+
accentIcon && !disabled && "text-primary"
|
|
1622
|
+
),
|
|
1623
|
+
children: leftElement
|
|
1624
|
+
}
|
|
1625
|
+
)
|
|
1626
|
+
] })
|
|
1627
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1628
|
+
Icon,
|
|
1629
|
+
{
|
|
1630
|
+
className: cn(
|
|
1631
|
+
accentIcon && !disabled && !hasAvatar && "text-primary"
|
|
1632
|
+
),
|
|
1633
|
+
iconLeft: leftElement,
|
|
1634
|
+
size: hasAvatar ? 24 : 18
|
|
1635
|
+
}
|
|
1636
|
+
) : null,
|
|
1637
|
+
children ?? text,
|
|
1638
|
+
rightElement ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { iconRight: rightElement, size: 18 }) : null
|
|
1639
|
+
]
|
|
1640
|
+
}
|
|
1641
|
+
);
|
|
1642
|
+
return removeButton ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex w-fit align-middle", children: [
|
|
1643
|
+
chip,
|
|
1644
|
+
removeButton
|
|
1645
|
+
] }) : chip;
|
|
1646
|
+
}
|
|
1647
|
+
function FloatingLabel({
|
|
1648
|
+
children,
|
|
1649
|
+
className,
|
|
1650
|
+
floating,
|
|
1651
|
+
floatingClassName,
|
|
1652
|
+
htmlFor,
|
|
1653
|
+
restingClassName
|
|
1654
|
+
}) {
|
|
1655
|
+
const floatingRef = react.useRef(null);
|
|
1656
|
+
const restingRef = react.useRef(null);
|
|
1657
|
+
const animationRef = react.useRef(null);
|
|
1658
|
+
const prevFloating = react.useRef(floating);
|
|
1659
|
+
const [animating, setAnimating] = react.useState(false);
|
|
1660
|
+
useIsomorphicLayoutEffect(() => {
|
|
1661
|
+
if (prevFloating.current === floating) return;
|
|
1662
|
+
prevFloating.current = floating;
|
|
1663
|
+
const floatingEl = floatingRef.current;
|
|
1664
|
+
const restingEl = restingRef.current;
|
|
1665
|
+
if (!floatingEl || !restingEl) return;
|
|
1666
|
+
const f = floatingEl.getBoundingClientRect();
|
|
1667
|
+
const r = restingEl.getBoundingClientRect();
|
|
1668
|
+
if (!f.width || !r.width) return;
|
|
1669
|
+
const scale = r.width / f.width;
|
|
1670
|
+
const xDelta = r.x - f.x;
|
|
1671
|
+
const yDelta = r.y - f.y + Math.round((r.height - f.height * scale) / 2);
|
|
1672
|
+
const rest = `translateX(${xDelta}px) translateY(${yDelta}px) scale(${scale})`;
|
|
1673
|
+
const float = `translateX(0) translateY(0) scale(1)`;
|
|
1674
|
+
animationRef.current?.cancel();
|
|
1675
|
+
setAnimating(true);
|
|
1676
|
+
const animation = floatingEl.animate(
|
|
1677
|
+
{ transform: floating ? [rest, float] : [float, rest] },
|
|
1678
|
+
{
|
|
1679
|
+
duration: 150,
|
|
1680
|
+
easing: "cubic-bezier(0.2, 0, 0, 1)",
|
|
1681
|
+
fill: "forwards"
|
|
1682
|
+
}
|
|
1683
|
+
);
|
|
1684
|
+
animationRef.current = animation;
|
|
1685
|
+
const done = () => {
|
|
1686
|
+
if (animationRef.current === animation) setAnimating(false);
|
|
1687
|
+
};
|
|
1688
|
+
animation.addEventListener("finish", done);
|
|
1689
|
+
animation.addEventListener("cancel", done);
|
|
1690
|
+
}, [floating]);
|
|
1691
|
+
useIsomorphicLayoutEffect(() => {
|
|
1692
|
+
if (animating || !animationRef.current) return;
|
|
1693
|
+
animationRef.current.cancel();
|
|
1694
|
+
animationRef.current = null;
|
|
1695
|
+
}, [animating]);
|
|
1696
|
+
const showFloating = floating || animating;
|
|
1697
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1698
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1699
|
+
"label",
|
|
1700
|
+
{
|
|
1701
|
+
"aria-hidden": true,
|
|
1702
|
+
className: cn(
|
|
1703
|
+
"pointer-events-none absolute",
|
|
1704
|
+
floatingClassName,
|
|
1705
|
+
className,
|
|
1706
|
+
!showFloating && "opacity-0"
|
|
1707
|
+
),
|
|
1708
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block origin-top-left", ref: floatingRef, children })
|
|
1709
|
+
}
|
|
1710
|
+
),
|
|
1711
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1712
|
+
"label",
|
|
1713
|
+
{
|
|
1714
|
+
className: cn(
|
|
1715
|
+
"pointer-events-none absolute",
|
|
1716
|
+
restingClassName,
|
|
1717
|
+
className,
|
|
1718
|
+
showFloating && "opacity-0"
|
|
1719
|
+
),
|
|
1720
|
+
htmlFor,
|
|
1721
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block", ref: restingRef, children })
|
|
1722
|
+
}
|
|
1723
|
+
)
|
|
1724
|
+
] });
|
|
1725
|
+
}
|
|
1726
|
+
function useFieldState(value, defaultValue, disabled) {
|
|
1727
|
+
const [focused, setFocusedState] = react.useState(false);
|
|
1728
|
+
const [internalHasValue, setInternalHasValue] = react.useState(
|
|
1729
|
+
defaultValue !== void 0 && defaultValue !== null && String(defaultValue).length > 0
|
|
1730
|
+
);
|
|
1731
|
+
const hasValue = value !== void 0 && value !== null ? String(value).length > 0 : internalHasValue;
|
|
1732
|
+
return {
|
|
1733
|
+
focused: focused && !disabled,
|
|
1734
|
+
hasValue,
|
|
1735
|
+
setFocused: setFocusedState,
|
|
1736
|
+
setInternalHasValue
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
function labelColor(opts) {
|
|
1740
|
+
if (opts.disabled) return "text-on-surface/38";
|
|
1741
|
+
if (opts.error) return "text-error";
|
|
1742
|
+
if (opts.focused) return "text-primary";
|
|
1743
|
+
return "text-on-surface-variant";
|
|
1744
|
+
}
|
|
1745
|
+
function SupportingText({
|
|
1746
|
+
error,
|
|
1747
|
+
errorText,
|
|
1748
|
+
id,
|
|
1749
|
+
supportingText
|
|
1750
|
+
}) {
|
|
1751
|
+
const isError = !!(error && errorText);
|
|
1752
|
+
const text = isError ? errorText : supportingText;
|
|
1753
|
+
if (!text) return null;
|
|
1754
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1755
|
+
"p",
|
|
1756
|
+
{
|
|
1757
|
+
role: isError ? "alert" : void 0,
|
|
1758
|
+
id,
|
|
1759
|
+
className: cn(
|
|
1760
|
+
"px-4 pt-1 text-body-small",
|
|
1761
|
+
error ? "text-error" : "text-on-surface-variant"
|
|
1762
|
+
),
|
|
1763
|
+
children: text
|
|
1764
|
+
}
|
|
1765
|
+
);
|
|
1766
|
+
}
|
|
1767
|
+
function FieldIcon({
|
|
1768
|
+
children,
|
|
1769
|
+
className
|
|
1770
|
+
}) {
|
|
1771
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1772
|
+
"span",
|
|
1773
|
+
{
|
|
1774
|
+
className: cn(
|
|
1775
|
+
"pointer-events-auto absolute flex h-6 w-6 items-center justify-center leading-none text-on-surface-variant",
|
|
1776
|
+
className
|
|
1777
|
+
),
|
|
1778
|
+
children
|
|
1779
|
+
}
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1782
|
+
function useControlled(controlled, defaultValue) {
|
|
1783
|
+
const isControlled = react.useRef(controlled !== void 0).current;
|
|
1784
|
+
const [internal, setInternal] = react.useState(defaultValue);
|
|
1785
|
+
const value = isControlled && controlled !== void 0 ? controlled : internal;
|
|
1786
|
+
const setValue = react.useCallback(
|
|
1787
|
+
(next) => {
|
|
1788
|
+
if (!isControlled) setInternal(next);
|
|
1789
|
+
},
|
|
1790
|
+
[isControlled]
|
|
1791
|
+
);
|
|
1792
|
+
return [value, setValue];
|
|
1793
|
+
}
|
|
1794
|
+
var TYPEAHEAD_BUFFER_MS = 200;
|
|
1795
|
+
function optionText(option) {
|
|
1796
|
+
return typeof option.label === "string" ? option.label : option.value;
|
|
1797
|
+
}
|
|
1798
|
+
function useSelect({
|
|
1799
|
+
defaultValue,
|
|
1800
|
+
disabled,
|
|
1801
|
+
onChange,
|
|
1802
|
+
options,
|
|
1803
|
+
value: valueProp
|
|
1804
|
+
}) {
|
|
1805
|
+
const [value, setValue] = useControlled(valueProp, defaultValue ?? "");
|
|
1806
|
+
const [isOpen, setIsOpen] = react.useState(false);
|
|
1807
|
+
const [focused, setFocused] = react.useState(false);
|
|
1808
|
+
const [highlighted, setHighlighted] = react.useState(-1);
|
|
1809
|
+
const wrapper = react.useRef(null);
|
|
1810
|
+
const typeahead = react.useRef({ buffer: "", time: 0 });
|
|
1811
|
+
const { exiting, mounted } = useDismissable(isOpen, 150);
|
|
1812
|
+
useOutsideClose(wrapper, () => setIsOpen(false), isOpen);
|
|
1813
|
+
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
1814
|
+
const move = (start, delta) => {
|
|
1815
|
+
for (let step = 1; step <= options.length; step += 1) {
|
|
1816
|
+
const index = (start + delta * step + options.length * step) % options.length;
|
|
1817
|
+
if (!options[index]?.disabled) return index;
|
|
1818
|
+
}
|
|
1819
|
+
return -1;
|
|
1820
|
+
};
|
|
1821
|
+
const openMenu = () => {
|
|
1822
|
+
if (disabled) return;
|
|
1823
|
+
setHighlighted(
|
|
1824
|
+
selectedIndex >= 0 && !options[selectedIndex]?.disabled ? selectedIndex : move(-1, 1)
|
|
1825
|
+
);
|
|
1826
|
+
setIsOpen(true);
|
|
1827
|
+
};
|
|
1828
|
+
const commit = (next) => {
|
|
1829
|
+
setValue(next);
|
|
1830
|
+
onChange?.(next);
|
|
1831
|
+
setIsOpen(false);
|
|
1832
|
+
};
|
|
1833
|
+
const typeaheadFind = (char) => {
|
|
1834
|
+
const now = Date.now();
|
|
1835
|
+
const stale = now - typeahead.current.time > TYPEAHEAD_BUFFER_MS;
|
|
1836
|
+
typeahead.current = {
|
|
1837
|
+
buffer: (stale ? "" : typeahead.current.buffer) + char.toLowerCase(),
|
|
1838
|
+
time: now
|
|
1839
|
+
};
|
|
1840
|
+
return options.findIndex(
|
|
1841
|
+
(option) => !option.disabled && optionText(option).toLowerCase().startsWith(typeahead.current.buffer)
|
|
1842
|
+
);
|
|
1843
|
+
};
|
|
1844
|
+
const handleKeyDown = (event) => {
|
|
1845
|
+
if (disabled) return;
|
|
1846
|
+
const { key } = event;
|
|
1847
|
+
const printable = key.length === 1 && key !== " " && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
1848
|
+
if (!isOpen) {
|
|
1849
|
+
if (["ArrowDown", "ArrowUp", "Enter", " "].includes(key)) {
|
|
1850
|
+
event.preventDefault();
|
|
1851
|
+
openMenu();
|
|
1852
|
+
} else if (printable) {
|
|
1853
|
+
const index = typeaheadFind(key);
|
|
1854
|
+
if (index >= 0) {
|
|
1855
|
+
setValue(options[index].value);
|
|
1856
|
+
onChange?.(options[index].value);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1861
|
+
switch (key) {
|
|
1862
|
+
case "ArrowDown":
|
|
1863
|
+
event.preventDefault();
|
|
1864
|
+
setHighlighted((current) => move(current, 1));
|
|
1865
|
+
break;
|
|
1866
|
+
case "ArrowUp":
|
|
1867
|
+
event.preventDefault();
|
|
1868
|
+
setHighlighted((current) => move(current, -1));
|
|
1869
|
+
break;
|
|
1870
|
+
case "Home":
|
|
1871
|
+
event.preventDefault();
|
|
1872
|
+
setHighlighted(move(-1, 1));
|
|
1873
|
+
break;
|
|
1874
|
+
case "End":
|
|
1875
|
+
event.preventDefault();
|
|
1876
|
+
setHighlighted(move(options.length, -1));
|
|
1877
|
+
break;
|
|
1878
|
+
case "Enter":
|
|
1879
|
+
case " ": {
|
|
1880
|
+
event.preventDefault();
|
|
1881
|
+
const option = options[highlighted];
|
|
1882
|
+
if (option && !option.disabled) commit(option.value);
|
|
1883
|
+
break;
|
|
1884
|
+
}
|
|
1885
|
+
case "Escape":
|
|
1886
|
+
event.preventDefault();
|
|
1887
|
+
setIsOpen(false);
|
|
1888
|
+
break;
|
|
1889
|
+
case "Tab":
|
|
1890
|
+
setIsOpen(false);
|
|
1891
|
+
break;
|
|
1892
|
+
default:
|
|
1893
|
+
if (printable) {
|
|
1894
|
+
const index = typeaheadFind(key);
|
|
1895
|
+
if (index >= 0) setHighlighted(index);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
};
|
|
1899
|
+
return {
|
|
1900
|
+
commit,
|
|
1901
|
+
exiting,
|
|
1902
|
+
focused: focused && !disabled,
|
|
1903
|
+
handleKeyDown,
|
|
1904
|
+
highlighted,
|
|
1905
|
+
isOpen,
|
|
1906
|
+
mounted,
|
|
1907
|
+
openMenu,
|
|
1908
|
+
selectedIndex,
|
|
1909
|
+
setFocused,
|
|
1910
|
+
setHighlighted,
|
|
1911
|
+
setIsOpen,
|
|
1912
|
+
value,
|
|
1913
|
+
wrapper
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
function SelectMenu({
|
|
1917
|
+
baseId,
|
|
1918
|
+
exiting,
|
|
1919
|
+
highlighted,
|
|
1920
|
+
onHighlight,
|
|
1921
|
+
onSelect,
|
|
1922
|
+
options,
|
|
1923
|
+
value
|
|
1924
|
+
}) {
|
|
1925
|
+
react.useEffect(() => {
|
|
1926
|
+
if (highlighted < 0) return;
|
|
1927
|
+
document.getElementById(`${baseId}-opt-${highlighted}`)?.scrollIntoView({ block: "nearest" });
|
|
1928
|
+
}, [baseId, highlighted]);
|
|
1929
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1930
|
+
"ul",
|
|
1931
|
+
{
|
|
1932
|
+
className: cn(
|
|
1933
|
+
"absolute top-full left-0 z-[var(--md-sys-z-dropdown)] mt-1 flex max-h-[280px] w-full min-w-max flex-col overflow-hidden overflow-y-auto rounded-large bg-surface-container-low py-0.5 shadow-mm-3 [--menu-clip-bleed:-24px]",
|
|
1934
|
+
exiting ? "animate-menu-out" : "animate-menu-in"
|
|
1935
|
+
),
|
|
1936
|
+
id: `${baseId}-listbox`,
|
|
1937
|
+
role: "listbox",
|
|
1938
|
+
children: options.map((option, index) => {
|
|
1939
|
+
const isSelected = option.value === value;
|
|
1940
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1941
|
+
"li",
|
|
1942
|
+
{
|
|
1943
|
+
"aria-disabled": option.disabled || void 0,
|
|
1944
|
+
"aria-selected": isSelected,
|
|
1945
|
+
className: cn(
|
|
1946
|
+
"mx-1 my-0.5 flex h-11 shrink-0 cursor-pointer items-center rounded-extra-small px-3 text-label-large first:rounded-t-medium last:rounded-b-medium",
|
|
1947
|
+
isSelected ? "rounded-medium bg-tertiary-container text-on-tertiary-container" : "text-on-surface",
|
|
1948
|
+
highlighted === index && !isSelected && "bg-on-surface/8",
|
|
1949
|
+
option.disabled && "cursor-not-allowed text-on-surface/38"
|
|
1950
|
+
),
|
|
1951
|
+
id: `${baseId}-opt-${index}`,
|
|
1952
|
+
onClick: () => {
|
|
1953
|
+
if (!option.disabled) onSelect(option.value);
|
|
1954
|
+
},
|
|
1955
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
1956
|
+
onMouseEnter: () => {
|
|
1957
|
+
if (!option.disabled) onHighlight(index);
|
|
1958
|
+
},
|
|
1959
|
+
role: "option",
|
|
1960
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: option.label ?? option.value })
|
|
1961
|
+
},
|
|
1962
|
+
option.value
|
|
1963
|
+
);
|
|
1964
|
+
})
|
|
1965
|
+
}
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
function SelectCaret({ open = false }) {
|
|
1969
|
+
const fade = "ease-md-linear transition-opacity delay-75 duration-75";
|
|
1970
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1971
|
+
"svg",
|
|
1972
|
+
{
|
|
1973
|
+
"aria-hidden": true,
|
|
1974
|
+
fill: "currentColor",
|
|
1975
|
+
height: 24,
|
|
1976
|
+
viewBox: "0 0 24 24",
|
|
1977
|
+
width: 24,
|
|
1978
|
+
children: [
|
|
1979
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1980
|
+
"path",
|
|
1981
|
+
{
|
|
1982
|
+
className: cn(fade, open ? "opacity-0" : "opacity-100"),
|
|
1983
|
+
d: "M7 10l5 5 5-5z"
|
|
1984
|
+
}
|
|
1985
|
+
),
|
|
1986
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1987
|
+
"path",
|
|
1988
|
+
{
|
|
1989
|
+
className: cn(fade, open ? "opacity-100" : "opacity-0"),
|
|
1990
|
+
d: "M7 15l5-5 5 5z"
|
|
1991
|
+
}
|
|
1992
|
+
)
|
|
1993
|
+
]
|
|
1994
|
+
}
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1997
|
+
var COMBOBOX_LABELS = {
|
|
1998
|
+
clear: "Clear",
|
|
1999
|
+
empty: "No results",
|
|
2000
|
+
loading: "Loading\u2026"
|
|
2001
|
+
};
|
|
2002
|
+
function useCombobox({
|
|
2003
|
+
defaultValue,
|
|
2004
|
+
disabled,
|
|
2005
|
+
onChange,
|
|
2006
|
+
onInputChange,
|
|
2007
|
+
options,
|
|
2008
|
+
value: valueProp
|
|
2009
|
+
}) {
|
|
2010
|
+
const [value, setValue] = useControlled(valueProp, defaultValue ?? "");
|
|
2011
|
+
const labelFor = (next) => options.find((option) => option.value === next)?.label ?? next;
|
|
2012
|
+
const [query, setQuery] = react.useState(() => value ? labelFor(value) : "");
|
|
2013
|
+
const [isOpen, setIsOpen] = react.useState(false);
|
|
2014
|
+
const [focused, setFocused] = react.useState(false);
|
|
2015
|
+
const [highlighted, setHighlighted] = react.useState(-1);
|
|
2016
|
+
const wrapper = react.useRef(null);
|
|
2017
|
+
const input = react.useRef(null);
|
|
2018
|
+
const { exiting, mounted } = useDismissable(isOpen, 150);
|
|
2019
|
+
react.useEffect(() => {
|
|
2020
|
+
if (!isOpen) setQuery(value ? labelFor(value) : "");
|
|
2021
|
+
}, [isOpen, value]);
|
|
2022
|
+
const move = (start, delta) => {
|
|
2023
|
+
if (options.length === 0) return -1;
|
|
2024
|
+
for (let step = 1; step <= options.length; step += 1) {
|
|
2025
|
+
const index = (start + delta * step + options.length * step) % options.length;
|
|
2026
|
+
if (!options[index]?.disabled) return index;
|
|
2027
|
+
}
|
|
2028
|
+
return -1;
|
|
2029
|
+
};
|
|
2030
|
+
const open = () => {
|
|
2031
|
+
if (disabled) return;
|
|
2032
|
+
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
2033
|
+
setHighlighted(
|
|
2034
|
+
selectedIndex >= 0 && !options[selectedIndex]?.disabled ? selectedIndex : move(-1, 1)
|
|
2035
|
+
);
|
|
2036
|
+
setIsOpen(true);
|
|
2037
|
+
};
|
|
2038
|
+
const closeAndRevert = () => {
|
|
2039
|
+
setIsOpen(false);
|
|
2040
|
+
setHighlighted(-1);
|
|
2041
|
+
setQuery(value ? labelFor(value) : "");
|
|
2042
|
+
};
|
|
2043
|
+
useOutsideClose(wrapper, closeAndRevert, isOpen);
|
|
2044
|
+
const onType = (next) => {
|
|
2045
|
+
setQuery(next);
|
|
2046
|
+
setIsOpen(true);
|
|
2047
|
+
setHighlighted(-1);
|
|
2048
|
+
onInputChange?.(next);
|
|
2049
|
+
};
|
|
2050
|
+
const commit = (next) => {
|
|
2051
|
+
setValue(next);
|
|
2052
|
+
onChange?.(next);
|
|
2053
|
+
setQuery(labelFor(next));
|
|
2054
|
+
setIsOpen(false);
|
|
2055
|
+
setHighlighted(-1);
|
|
2056
|
+
};
|
|
2057
|
+
const clear = () => {
|
|
2058
|
+
setValue("");
|
|
2059
|
+
onChange?.("");
|
|
2060
|
+
setQuery("");
|
|
2061
|
+
setHighlighted(-1);
|
|
2062
|
+
onInputChange?.("");
|
|
2063
|
+
input.current?.focus();
|
|
2064
|
+
};
|
|
2065
|
+
const handleKeyDown = (event) => {
|
|
2066
|
+
if (disabled) return;
|
|
2067
|
+
switch (event.key) {
|
|
2068
|
+
case "ArrowDown":
|
|
2069
|
+
event.preventDefault();
|
|
2070
|
+
if (isOpen) setHighlighted((current) => move(current, 1));
|
|
2071
|
+
else open();
|
|
2072
|
+
break;
|
|
2073
|
+
case "ArrowUp":
|
|
2074
|
+
event.preventDefault();
|
|
2075
|
+
if (isOpen) setHighlighted((current) => move(current, -1));
|
|
2076
|
+
else open();
|
|
2077
|
+
break;
|
|
2078
|
+
case "Home":
|
|
2079
|
+
if (isOpen) {
|
|
2080
|
+
event.preventDefault();
|
|
2081
|
+
setHighlighted(move(-1, 1));
|
|
2082
|
+
}
|
|
2083
|
+
break;
|
|
2084
|
+
case "End":
|
|
2085
|
+
if (isOpen) {
|
|
2086
|
+
event.preventDefault();
|
|
2087
|
+
setHighlighted(move(options.length, -1));
|
|
2088
|
+
}
|
|
2089
|
+
break;
|
|
2090
|
+
case "Enter":
|
|
2091
|
+
if (isOpen && highlighted >= 0) {
|
|
2092
|
+
event.preventDefault();
|
|
2093
|
+
const option = options[highlighted];
|
|
2094
|
+
if (option && !option.disabled) commit(option.value);
|
|
2095
|
+
}
|
|
2096
|
+
break;
|
|
2097
|
+
case "Escape":
|
|
2098
|
+
if (isOpen) {
|
|
2099
|
+
event.preventDefault();
|
|
2100
|
+
closeAndRevert();
|
|
2101
|
+
}
|
|
2102
|
+
break;
|
|
2103
|
+
case "Tab":
|
|
2104
|
+
if (isOpen) closeAndRevert();
|
|
2105
|
+
break;
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
return {
|
|
2109
|
+
clear,
|
|
2110
|
+
commit,
|
|
2111
|
+
exiting,
|
|
2112
|
+
focused: focused && !disabled,
|
|
2113
|
+
handleKeyDown,
|
|
2114
|
+
highlighted,
|
|
2115
|
+
input,
|
|
2116
|
+
isOpen,
|
|
2117
|
+
mounted,
|
|
2118
|
+
onType,
|
|
2119
|
+
query,
|
|
2120
|
+
setFocused,
|
|
2121
|
+
setHighlighted,
|
|
2122
|
+
setIsOpen,
|
|
2123
|
+
value,
|
|
2124
|
+
wrapper
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
function CloseGlyph() {
|
|
2128
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": true, fill: "currentColor", height: 18, viewBox: "0 0 24 24", width: 18, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" }) });
|
|
2129
|
+
}
|
|
2130
|
+
function ComboboxTrailing({
|
|
2131
|
+
clearLabel,
|
|
2132
|
+
disabled,
|
|
2133
|
+
error,
|
|
2134
|
+
isOpen,
|
|
2135
|
+
onClear,
|
|
2136
|
+
showClear
|
|
2137
|
+
}) {
|
|
2138
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute top-1/2 right-2 flex -translate-y-1/2 items-center gap-1", children: [
|
|
2139
|
+
showClear ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2140
|
+
"button",
|
|
2141
|
+
{
|
|
2142
|
+
"aria-label": clearLabel,
|
|
2143
|
+
className: "state-layer pointer-events-auto flex h-6 w-6 cursor-pointer items-center justify-center rounded-full text-on-surface-variant",
|
|
2144
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2145
|
+
onClick: onClear,
|
|
2146
|
+
type: "button",
|
|
2147
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CloseGlyph, {})
|
|
2148
|
+
}
|
|
2149
|
+
) : null,
|
|
2150
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2151
|
+
"span",
|
|
2152
|
+
{
|
|
2153
|
+
className: cn(
|
|
2154
|
+
"flex h-6 w-6 items-center justify-center text-on-surface-variant",
|
|
2155
|
+
error && "text-error",
|
|
2156
|
+
disabled && "text-on-surface/38"
|
|
2157
|
+
),
|
|
2158
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SelectCaret, { open: isOpen })
|
|
2159
|
+
}
|
|
2160
|
+
)
|
|
2161
|
+
] });
|
|
2162
|
+
}
|
|
2163
|
+
function ComboboxListbox({
|
|
2164
|
+
anchorRef,
|
|
2165
|
+
baseId,
|
|
2166
|
+
emptyText,
|
|
2167
|
+
exiting,
|
|
2168
|
+
highlighted,
|
|
2169
|
+
listboxClassName,
|
|
2170
|
+
loading,
|
|
2171
|
+
loadingText,
|
|
2172
|
+
onHighlight,
|
|
2173
|
+
onSelect,
|
|
2174
|
+
options,
|
|
2175
|
+
value
|
|
2176
|
+
}) {
|
|
2177
|
+
const floating = react.useRef(null);
|
|
2178
|
+
const pos = usePopoverPosition(anchorRef, floating, true, {
|
|
2179
|
+
gap: 4,
|
|
2180
|
+
matchWidth: true,
|
|
2181
|
+
placement: "bottom-start"
|
|
2182
|
+
});
|
|
2183
|
+
react.useEffect(() => {
|
|
2184
|
+
if (highlighted < 0) return;
|
|
2185
|
+
document.getElementById(`${baseId}-opt-${highlighted}`)?.scrollIntoView?.({ block: "nearest" });
|
|
2186
|
+
}, [baseId, highlighted]);
|
|
2187
|
+
if (typeof document === "undefined") return null;
|
|
2188
|
+
const anim = exiting ? "animate-menu-out" : "animate-menu-in";
|
|
2189
|
+
const surface = "max-h-[280px] w-full overflow-hidden overflow-y-auto rounded-large bg-surface-container-low py-0.5 shadow-mm-3 [--menu-clip-bleed:-24px]";
|
|
2190
|
+
return reactDom.createPortal(
|
|
2191
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2192
|
+
"div",
|
|
2193
|
+
{
|
|
2194
|
+
className: "fixed z-[var(--md-sys-z-menu)]",
|
|
2195
|
+
ref: floating,
|
|
2196
|
+
style: { left: pos.left, top: pos.top, width: pos.width },
|
|
2197
|
+
children: loading || options.length === 0 ? (
|
|
2198
|
+
// An empty listbox is an a11y violation — show a status row instead.
|
|
2199
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2200
|
+
"div",
|
|
2201
|
+
{
|
|
2202
|
+
"aria-live": "polite",
|
|
2203
|
+
className: cn(
|
|
2204
|
+
surface,
|
|
2205
|
+
anim,
|
|
2206
|
+
"px-4 py-3 text-body-medium text-on-surface-variant",
|
|
2207
|
+
listboxClassName
|
|
2208
|
+
),
|
|
2209
|
+
role: "status",
|
|
2210
|
+
children: loading ? loadingText : emptyText
|
|
2211
|
+
}
|
|
2212
|
+
)
|
|
2213
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2214
|
+
"ul",
|
|
2215
|
+
{
|
|
2216
|
+
className: cn("flex flex-col", surface, anim, listboxClassName),
|
|
2217
|
+
id: `${baseId}-listbox`,
|
|
2218
|
+
role: "listbox",
|
|
2219
|
+
children: options.map((option, index) => {
|
|
2220
|
+
const isSelected = option.value === value;
|
|
2221
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2222
|
+
"li",
|
|
2223
|
+
{
|
|
2224
|
+
"aria-disabled": option.disabled || void 0,
|
|
2225
|
+
"aria-selected": isSelected,
|
|
2226
|
+
className: cn(
|
|
2227
|
+
"mx-1 my-0.5 flex h-11 shrink-0 cursor-pointer items-center rounded-extra-small px-3 text-label-large first:rounded-t-medium last:rounded-b-medium",
|
|
2228
|
+
isSelected ? "rounded-medium bg-tertiary-container text-on-tertiary-container" : "text-on-surface",
|
|
2229
|
+
highlighted === index && !isSelected && "bg-on-surface/8",
|
|
2230
|
+
option.disabled && "cursor-not-allowed text-on-surface/38"
|
|
2231
|
+
),
|
|
2232
|
+
id: `${baseId}-opt-${index}`,
|
|
2233
|
+
onClick: () => {
|
|
2234
|
+
if (!option.disabled) onSelect(option.value);
|
|
2235
|
+
},
|
|
2236
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2237
|
+
onMouseEnter: () => {
|
|
2238
|
+
if (!option.disabled) onHighlight(index);
|
|
2239
|
+
},
|
|
2240
|
+
role: "option",
|
|
2241
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: option.label ?? option.value })
|
|
2242
|
+
},
|
|
2243
|
+
option.value
|
|
2244
|
+
);
|
|
2245
|
+
})
|
|
2246
|
+
}
|
|
2247
|
+
)
|
|
2248
|
+
}
|
|
2249
|
+
),
|
|
2250
|
+
document.body
|
|
2251
|
+
);
|
|
2252
|
+
}
|
|
2253
|
+
function ComboboxFilled({
|
|
2254
|
+
className,
|
|
2255
|
+
clearable = true,
|
|
2256
|
+
defaultValue,
|
|
2257
|
+
disabled,
|
|
2258
|
+
error,
|
|
2259
|
+
errorText,
|
|
2260
|
+
id,
|
|
2261
|
+
inputClassName,
|
|
2262
|
+
label,
|
|
2263
|
+
labels,
|
|
2264
|
+
leftElement,
|
|
2265
|
+
listboxClassName,
|
|
2266
|
+
loading,
|
|
2267
|
+
name,
|
|
2268
|
+
onChange,
|
|
2269
|
+
onInputChange,
|
|
2270
|
+
options,
|
|
2271
|
+
supportingText,
|
|
2272
|
+
value: valueProp,
|
|
2273
|
+
...inputProps
|
|
2274
|
+
}) {
|
|
2275
|
+
const l = { ...COMBOBOX_LABELS, ...labels };
|
|
2276
|
+
const autoId = react.useId();
|
|
2277
|
+
const inputId = id ?? `${autoId}-input`;
|
|
2278
|
+
const {
|
|
2279
|
+
clear,
|
|
2280
|
+
commit,
|
|
2281
|
+
exiting,
|
|
2282
|
+
focused,
|
|
2283
|
+
handleKeyDown,
|
|
2284
|
+
highlighted,
|
|
2285
|
+
input,
|
|
2286
|
+
isOpen,
|
|
2287
|
+
mounted,
|
|
2288
|
+
onType,
|
|
2289
|
+
query,
|
|
2290
|
+
setFocused,
|
|
2291
|
+
setHighlighted,
|
|
2292
|
+
setIsOpen,
|
|
2293
|
+
value,
|
|
2294
|
+
wrapper
|
|
2295
|
+
} = useCombobox({
|
|
2296
|
+
defaultValue,
|
|
2297
|
+
disabled,
|
|
2298
|
+
onChange,
|
|
2299
|
+
onInputChange,
|
|
2300
|
+
options,
|
|
2301
|
+
value: valueProp
|
|
2302
|
+
});
|
|
2303
|
+
const active = focused || isOpen;
|
|
2304
|
+
const floating = active || query.length > 0;
|
|
2305
|
+
const showClear = clearable && query.length > 0 && !disabled;
|
|
2306
|
+
const hasOptions = !loading && options.length > 0;
|
|
2307
|
+
const describedById = error && errorText || supportingText ? `${autoId}-support` : void 0;
|
|
2308
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), children: [
|
|
2309
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: wrapper, children: [
|
|
2310
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative flex h-14 w-full overflow-hidden rounded-t-small", children: [
|
|
2311
|
+
leftElement ? /* @__PURE__ */ jsxRuntime.jsx(FieldIcon, { className: "top-1/2 left-3 z-10 -translate-y-1/2", children: leftElement }) : null,
|
|
2312
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2313
|
+
"input",
|
|
2314
|
+
{
|
|
2315
|
+
...inputProps,
|
|
2316
|
+
"aria-activedescendant": isOpen && hasOptions && highlighted >= 0 ? `${autoId}-opt-${highlighted}` : void 0,
|
|
2317
|
+
"aria-autocomplete": onInputChange ? "list" : "none",
|
|
2318
|
+
"aria-controls": mounted && hasOptions ? `${autoId}-listbox` : void 0,
|
|
2319
|
+
"aria-describedby": describedById,
|
|
2320
|
+
"aria-expanded": isOpen,
|
|
2321
|
+
"aria-invalid": error || void 0,
|
|
2322
|
+
autoComplete: "off",
|
|
2323
|
+
className: cn(
|
|
2324
|
+
"h-14 w-full bg-surface-container-highest text-body-large text-on-surface outline-none disabled:cursor-not-allowed disabled:bg-on-surface/4 disabled:text-on-surface/38",
|
|
2325
|
+
label ? "pt-5 pb-1" : "",
|
|
2326
|
+
leftElement ? "pl-12" : "pl-4",
|
|
2327
|
+
showClear ? "pr-20" : "pr-12",
|
|
2328
|
+
inputClassName
|
|
2329
|
+
),
|
|
2330
|
+
disabled,
|
|
2331
|
+
id: inputId,
|
|
2332
|
+
onBlur: () => setFocused(false),
|
|
2333
|
+
onChange: (event) => onType(event.target.value),
|
|
2334
|
+
onClick: () => {
|
|
2335
|
+
if (!disabled) setIsOpen(true);
|
|
2336
|
+
},
|
|
2337
|
+
onFocus: () => setFocused(true),
|
|
2338
|
+
onKeyDown: handleKeyDown,
|
|
2339
|
+
ref: input,
|
|
2340
|
+
role: "combobox",
|
|
2341
|
+
type: "text",
|
|
2342
|
+
value: query
|
|
2343
|
+
}
|
|
2344
|
+
),
|
|
2345
|
+
!disabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2346
|
+
"span",
|
|
2347
|
+
{
|
|
2348
|
+
"aria-hidden": true,
|
|
2349
|
+
className: "ease-md-linear pointer-events-none absolute inset-0 bg-on-surface opacity-0 transition-opacity duration-[15ms] group-hover:opacity-8"
|
|
2350
|
+
}
|
|
2351
|
+
) : null,
|
|
2352
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2353
|
+
"span",
|
|
2354
|
+
{
|
|
2355
|
+
"aria-hidden": true,
|
|
2356
|
+
className: cn(
|
|
2357
|
+
"pointer-events-none absolute inset-x-0 bottom-0 transition-all",
|
|
2358
|
+
error ? "bg-error" : active ? "bg-primary" : "bg-on-surface-variant",
|
|
2359
|
+
active || error ? "h-0.5" : "h-px",
|
|
2360
|
+
disabled && "bg-on-surface/38"
|
|
2361
|
+
)
|
|
2362
|
+
}
|
|
2363
|
+
),
|
|
2364
|
+
label ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2365
|
+
FloatingLabel,
|
|
2366
|
+
{
|
|
2367
|
+
className: labelColor({ disabled, error, focused: active }),
|
|
2368
|
+
floating,
|
|
2369
|
+
floatingClassName: cn(
|
|
2370
|
+
"top-2 text-body-small",
|
|
2371
|
+
leftElement ? "left-12" : "left-4"
|
|
2372
|
+
),
|
|
2373
|
+
htmlFor: inputId,
|
|
2374
|
+
restingClassName: cn(
|
|
2375
|
+
"top-1/2 -translate-y-1/2 text-body-large",
|
|
2376
|
+
leftElement ? "left-12" : "left-4"
|
|
2377
|
+
),
|
|
2378
|
+
children: label
|
|
2379
|
+
}
|
|
2380
|
+
) : null,
|
|
2381
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2382
|
+
ComboboxTrailing,
|
|
2383
|
+
{
|
|
2384
|
+
clearLabel: l.clear,
|
|
2385
|
+
disabled,
|
|
2386
|
+
error,
|
|
2387
|
+
isOpen,
|
|
2388
|
+
onClear: clear,
|
|
2389
|
+
showClear
|
|
2390
|
+
}
|
|
2391
|
+
)
|
|
2392
|
+
] }),
|
|
2393
|
+
mounted ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2394
|
+
ComboboxListbox,
|
|
2395
|
+
{
|
|
2396
|
+
anchorRef: wrapper,
|
|
2397
|
+
baseId: autoId,
|
|
2398
|
+
emptyText: l.empty,
|
|
2399
|
+
exiting,
|
|
2400
|
+
highlighted,
|
|
2401
|
+
listboxClassName,
|
|
2402
|
+
loading,
|
|
2403
|
+
loadingText: l.loading,
|
|
2404
|
+
onHighlight: setHighlighted,
|
|
2405
|
+
onSelect: commit,
|
|
2406
|
+
options,
|
|
2407
|
+
value
|
|
2408
|
+
}
|
|
2409
|
+
) : null
|
|
2410
|
+
] }),
|
|
2411
|
+
name ? /* @__PURE__ */ jsxRuntime.jsx("input", { name, type: "hidden", value }) : null,
|
|
2412
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2413
|
+
SupportingText,
|
|
2414
|
+
{
|
|
2415
|
+
error,
|
|
2416
|
+
errorText,
|
|
2417
|
+
id: describedById,
|
|
2418
|
+
supportingText
|
|
2419
|
+
}
|
|
2420
|
+
)
|
|
2421
|
+
] });
|
|
2422
|
+
}
|
|
2423
|
+
function ComboboxOutlined({
|
|
2424
|
+
className,
|
|
2425
|
+
clearable = true,
|
|
2426
|
+
defaultValue,
|
|
2427
|
+
disabled,
|
|
2428
|
+
error,
|
|
2429
|
+
errorText,
|
|
2430
|
+
id,
|
|
2431
|
+
inputClassName,
|
|
2432
|
+
label,
|
|
2433
|
+
labels,
|
|
2434
|
+
leftElement,
|
|
2435
|
+
listboxClassName,
|
|
2436
|
+
loading,
|
|
2437
|
+
name,
|
|
2438
|
+
onChange,
|
|
2439
|
+
onInputChange,
|
|
2440
|
+
options,
|
|
2441
|
+
supportingText,
|
|
2442
|
+
value: valueProp,
|
|
2443
|
+
...inputProps
|
|
2444
|
+
}) {
|
|
2445
|
+
const l = { ...COMBOBOX_LABELS, ...labels };
|
|
2446
|
+
const autoId = react.useId();
|
|
2447
|
+
const inputId = id ?? `${autoId}-input`;
|
|
2448
|
+
const {
|
|
2449
|
+
clear,
|
|
2450
|
+
commit,
|
|
2451
|
+
exiting,
|
|
2452
|
+
focused,
|
|
2453
|
+
handleKeyDown,
|
|
2454
|
+
highlighted,
|
|
2455
|
+
input,
|
|
2456
|
+
isOpen,
|
|
2457
|
+
mounted,
|
|
2458
|
+
onType,
|
|
2459
|
+
query,
|
|
2460
|
+
setFocused,
|
|
2461
|
+
setHighlighted,
|
|
2462
|
+
setIsOpen,
|
|
2463
|
+
value,
|
|
2464
|
+
wrapper
|
|
2465
|
+
} = useCombobox({
|
|
2466
|
+
defaultValue,
|
|
2467
|
+
disabled,
|
|
2468
|
+
onChange,
|
|
2469
|
+
onInputChange,
|
|
2470
|
+
options,
|
|
2471
|
+
value: valueProp
|
|
2472
|
+
});
|
|
2473
|
+
const active = focused || isOpen;
|
|
2474
|
+
const floating = active || query.length > 0;
|
|
2475
|
+
const showClear = clearable && query.length > 0 && !disabled;
|
|
2476
|
+
const hasOptions = !loading && options.length > 0;
|
|
2477
|
+
const describedById = error && errorText || supportingText ? `${autoId}-support` : void 0;
|
|
2478
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), children: [
|
|
2479
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: wrapper, children: [
|
|
2480
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative flex h-14 w-full", children: [
|
|
2481
|
+
leftElement ? /* @__PURE__ */ jsxRuntime.jsx(FieldIcon, { className: "top-1/2 left-3 -translate-y-1/2", children: leftElement }) : null,
|
|
2482
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2483
|
+
"input",
|
|
2484
|
+
{
|
|
2485
|
+
...inputProps,
|
|
2486
|
+
"aria-activedescendant": isOpen && hasOptions && highlighted >= 0 ? `${autoId}-opt-${highlighted}` : void 0,
|
|
2487
|
+
"aria-autocomplete": onInputChange ? "list" : "none",
|
|
2488
|
+
"aria-controls": mounted && hasOptions ? `${autoId}-listbox` : void 0,
|
|
2489
|
+
"aria-describedby": describedById,
|
|
2490
|
+
"aria-expanded": isOpen,
|
|
2491
|
+
"aria-invalid": error || void 0,
|
|
2492
|
+
autoComplete: "off",
|
|
2493
|
+
className: cn(
|
|
2494
|
+
"h-14 w-full bg-transparent text-body-large text-on-surface outline-none disabled:cursor-not-allowed disabled:text-on-surface/38",
|
|
2495
|
+
leftElement ? "pl-12" : "pl-4",
|
|
2496
|
+
showClear ? "pr-20" : "pr-12",
|
|
2497
|
+
inputClassName
|
|
2498
|
+
),
|
|
2499
|
+
disabled,
|
|
2500
|
+
id: inputId,
|
|
2501
|
+
onBlur: () => setFocused(false),
|
|
2502
|
+
onChange: (event) => onType(event.target.value),
|
|
2503
|
+
onClick: () => {
|
|
2504
|
+
if (!disabled) setIsOpen(true);
|
|
2505
|
+
},
|
|
2506
|
+
onFocus: () => setFocused(true),
|
|
2507
|
+
onKeyDown: handleKeyDown,
|
|
2508
|
+
ref: input,
|
|
2509
|
+
role: "combobox",
|
|
2510
|
+
type: "text",
|
|
2511
|
+
value: query
|
|
2512
|
+
}
|
|
2513
|
+
),
|
|
2514
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2515
|
+
"fieldset",
|
|
2516
|
+
{
|
|
2517
|
+
"aria-hidden": true,
|
|
2518
|
+
className: cn(
|
|
2519
|
+
"pointer-events-none absolute inset-0 m-0 min-w-0 rounded-small px-2 transition-colors",
|
|
2520
|
+
error ? active ? "border-2 border-error" : "border border-error" : active ? "border-2 border-primary" : "border border-outline group-hover:border-on-surface",
|
|
2521
|
+
disabled && "border-on-surface/12 group-hover:border-on-surface/12"
|
|
2522
|
+
),
|
|
2523
|
+
children: label ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2524
|
+
"legend",
|
|
1555
2525
|
{
|
|
1556
2526
|
className: cn(
|
|
1557
|
-
"
|
|
1558
|
-
|
|
1559
|
-
accentIcon && !disabled && "text-primary"
|
|
2527
|
+
"invisible h-0 px-0 text-body-small whitespace-nowrap transition-all",
|
|
2528
|
+
floating ? "max-w-full px-1" : "max-w-0"
|
|
1560
2529
|
),
|
|
1561
|
-
children:
|
|
2530
|
+
children: label
|
|
1562
2531
|
}
|
|
1563
|
-
)
|
|
1564
|
-
|
|
1565
|
-
)
|
|
1566
|
-
|
|
2532
|
+
) : null
|
|
2533
|
+
}
|
|
2534
|
+
),
|
|
2535
|
+
label ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2536
|
+
FloatingLabel,
|
|
1567
2537
|
{
|
|
1568
|
-
className:
|
|
1569
|
-
|
|
2538
|
+
className: labelColor({ disabled, error, focused: active }),
|
|
2539
|
+
floating,
|
|
2540
|
+
floatingClassName: "top-0 left-3 -translate-y-1/2 px-1 text-body-small",
|
|
2541
|
+
htmlFor: inputId,
|
|
2542
|
+
restingClassName: cn(
|
|
2543
|
+
"top-1/2 -translate-y-1/2 text-body-large",
|
|
2544
|
+
leftElement ? "left-12" : "left-4"
|
|
1570
2545
|
),
|
|
1571
|
-
|
|
1572
|
-
size: hasAvatar ? 24 : 18
|
|
2546
|
+
children: label
|
|
1573
2547
|
}
|
|
1574
2548
|
) : null,
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
2549
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2550
|
+
ComboboxTrailing,
|
|
2551
|
+
{
|
|
2552
|
+
clearLabel: l.clear,
|
|
2553
|
+
disabled,
|
|
2554
|
+
error,
|
|
2555
|
+
isOpen,
|
|
2556
|
+
onClear: clear,
|
|
2557
|
+
showClear
|
|
2558
|
+
}
|
|
2559
|
+
)
|
|
2560
|
+
] }),
|
|
2561
|
+
mounted ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2562
|
+
ComboboxListbox,
|
|
2563
|
+
{
|
|
2564
|
+
anchorRef: wrapper,
|
|
2565
|
+
baseId: autoId,
|
|
2566
|
+
emptyText: l.empty,
|
|
2567
|
+
exiting,
|
|
2568
|
+
highlighted,
|
|
2569
|
+
listboxClassName,
|
|
2570
|
+
loading,
|
|
2571
|
+
loadingText: l.loading,
|
|
2572
|
+
onHighlight: setHighlighted,
|
|
2573
|
+
onSelect: commit,
|
|
2574
|
+
options,
|
|
2575
|
+
value
|
|
2576
|
+
}
|
|
2577
|
+
) : null
|
|
2578
|
+
] }),
|
|
2579
|
+
name ? /* @__PURE__ */ jsxRuntime.jsx("input", { name, type: "hidden", value }) : null,
|
|
2580
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2581
|
+
SupportingText,
|
|
2582
|
+
{
|
|
2583
|
+
error,
|
|
2584
|
+
errorText,
|
|
2585
|
+
id: describedById,
|
|
2586
|
+
supportingText
|
|
2587
|
+
}
|
|
2588
|
+
)
|
|
2589
|
+
] });
|
|
1584
2590
|
}
|
|
1585
2591
|
function TableBody({ children, className, ...props }) {
|
|
1586
2592
|
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: cn("text-body-medium", className), ...props, children });
|
|
@@ -1756,7 +2762,7 @@ function Dialog({
|
|
|
1756
2762
|
"div",
|
|
1757
2763
|
{
|
|
1758
2764
|
className: cn(
|
|
1759
|
-
"fixed inset-0 z-
|
|
2765
|
+
"fixed inset-0 z-[var(--md-sys-z-modal)] flex items-center justify-center bg-scrim/32 p-4",
|
|
1760
2766
|
exiting ? "animate-scrim-out" : "animate-scrim-in"
|
|
1761
2767
|
),
|
|
1762
2768
|
onClick: handleScrim,
|
|
@@ -1785,141 +2791,6 @@ function Dialog({
|
|
|
1785
2791
|
Dialog.Header = DialogHeader;
|
|
1786
2792
|
Dialog.Body = DialogBody;
|
|
1787
2793
|
Dialog.Footer = DialogFooter;
|
|
1788
|
-
function FloatingLabel({
|
|
1789
|
-
children,
|
|
1790
|
-
className,
|
|
1791
|
-
floating,
|
|
1792
|
-
floatingClassName,
|
|
1793
|
-
htmlFor,
|
|
1794
|
-
restingClassName
|
|
1795
|
-
}) {
|
|
1796
|
-
const floatingRef = react.useRef(null);
|
|
1797
|
-
const restingRef = react.useRef(null);
|
|
1798
|
-
const animationRef = react.useRef(null);
|
|
1799
|
-
const prevFloating = react.useRef(floating);
|
|
1800
|
-
const [animating, setAnimating] = react.useState(false);
|
|
1801
|
-
useIsomorphicLayoutEffect(() => {
|
|
1802
|
-
if (prevFloating.current === floating) return;
|
|
1803
|
-
prevFloating.current = floating;
|
|
1804
|
-
const floatingEl = floatingRef.current;
|
|
1805
|
-
const restingEl = restingRef.current;
|
|
1806
|
-
if (!floatingEl || !restingEl) return;
|
|
1807
|
-
const f = floatingEl.getBoundingClientRect();
|
|
1808
|
-
const r = restingEl.getBoundingClientRect();
|
|
1809
|
-
if (!f.width || !r.width) return;
|
|
1810
|
-
const scale = r.width / f.width;
|
|
1811
|
-
const xDelta = r.x - f.x;
|
|
1812
|
-
const yDelta = r.y - f.y + Math.round((r.height - f.height * scale) / 2);
|
|
1813
|
-
const rest = `translateX(${xDelta}px) translateY(${yDelta}px) scale(${scale})`;
|
|
1814
|
-
const float = `translateX(0) translateY(0) scale(1)`;
|
|
1815
|
-
animationRef.current?.cancel();
|
|
1816
|
-
setAnimating(true);
|
|
1817
|
-
const animation = floatingEl.animate(
|
|
1818
|
-
{ transform: floating ? [rest, float] : [float, rest] },
|
|
1819
|
-
{
|
|
1820
|
-
duration: 150,
|
|
1821
|
-
easing: "cubic-bezier(0.2, 0, 0, 1)",
|
|
1822
|
-
fill: "forwards"
|
|
1823
|
-
}
|
|
1824
|
-
);
|
|
1825
|
-
animationRef.current = animation;
|
|
1826
|
-
const done = () => {
|
|
1827
|
-
if (animationRef.current === animation) setAnimating(false);
|
|
1828
|
-
};
|
|
1829
|
-
animation.addEventListener("finish", done);
|
|
1830
|
-
animation.addEventListener("cancel", done);
|
|
1831
|
-
}, [floating]);
|
|
1832
|
-
useIsomorphicLayoutEffect(() => {
|
|
1833
|
-
if (animating || !animationRef.current) return;
|
|
1834
|
-
animationRef.current.cancel();
|
|
1835
|
-
animationRef.current = null;
|
|
1836
|
-
}, [animating]);
|
|
1837
|
-
const showFloating = floating || animating;
|
|
1838
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1839
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1840
|
-
"label",
|
|
1841
|
-
{
|
|
1842
|
-
"aria-hidden": true,
|
|
1843
|
-
className: cn(
|
|
1844
|
-
"pointer-events-none absolute",
|
|
1845
|
-
floatingClassName,
|
|
1846
|
-
className,
|
|
1847
|
-
!showFloating && "opacity-0"
|
|
1848
|
-
),
|
|
1849
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block origin-top-left", ref: floatingRef, children })
|
|
1850
|
-
}
|
|
1851
|
-
),
|
|
1852
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1853
|
-
"label",
|
|
1854
|
-
{
|
|
1855
|
-
className: cn(
|
|
1856
|
-
"pointer-events-none absolute",
|
|
1857
|
-
restingClassName,
|
|
1858
|
-
className,
|
|
1859
|
-
showFloating && "opacity-0"
|
|
1860
|
-
),
|
|
1861
|
-
htmlFor,
|
|
1862
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block", ref: restingRef, children })
|
|
1863
|
-
}
|
|
1864
|
-
)
|
|
1865
|
-
] });
|
|
1866
|
-
}
|
|
1867
|
-
function useFieldState(value, defaultValue, disabled) {
|
|
1868
|
-
const [focused, setFocusedState] = react.useState(false);
|
|
1869
|
-
const [internalHasValue, setInternalHasValue] = react.useState(
|
|
1870
|
-
defaultValue !== void 0 && defaultValue !== null && String(defaultValue).length > 0
|
|
1871
|
-
);
|
|
1872
|
-
const hasValue = value !== void 0 && value !== null ? String(value).length > 0 : internalHasValue;
|
|
1873
|
-
return {
|
|
1874
|
-
focused: focused && !disabled,
|
|
1875
|
-
hasValue,
|
|
1876
|
-
setFocused: setFocusedState,
|
|
1877
|
-
setInternalHasValue
|
|
1878
|
-
};
|
|
1879
|
-
}
|
|
1880
|
-
function labelColor(opts) {
|
|
1881
|
-
if (opts.disabled) return "text-on-surface/38";
|
|
1882
|
-
if (opts.error) return "text-error";
|
|
1883
|
-
if (opts.focused) return "text-primary";
|
|
1884
|
-
return "text-on-surface-variant";
|
|
1885
|
-
}
|
|
1886
|
-
function SupportingText({
|
|
1887
|
-
error,
|
|
1888
|
-
errorText,
|
|
1889
|
-
id,
|
|
1890
|
-
supportingText
|
|
1891
|
-
}) {
|
|
1892
|
-
const isError = !!(error && errorText);
|
|
1893
|
-
const text = isError ? errorText : supportingText;
|
|
1894
|
-
if (!text) return null;
|
|
1895
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1896
|
-
"p",
|
|
1897
|
-
{
|
|
1898
|
-
role: isError ? "alert" : void 0,
|
|
1899
|
-
id,
|
|
1900
|
-
className: cn(
|
|
1901
|
-
"px-4 pt-1 text-body-small",
|
|
1902
|
-
error ? "text-error" : "text-on-surface-variant"
|
|
1903
|
-
),
|
|
1904
|
-
children: text
|
|
1905
|
-
}
|
|
1906
|
-
);
|
|
1907
|
-
}
|
|
1908
|
-
function FieldIcon({
|
|
1909
|
-
children,
|
|
1910
|
-
className
|
|
1911
|
-
}) {
|
|
1912
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1913
|
-
"span",
|
|
1914
|
-
{
|
|
1915
|
-
className: cn(
|
|
1916
|
-
"pointer-events-auto absolute flex h-6 w-6 items-center justify-center leading-none text-on-surface-variant",
|
|
1917
|
-
className
|
|
1918
|
-
),
|
|
1919
|
-
children
|
|
1920
|
-
}
|
|
1921
|
-
);
|
|
1922
|
-
}
|
|
1923
2794
|
function InputOutlined({
|
|
1924
2795
|
"aria-describedby": ariaDescribedBy,
|
|
1925
2796
|
"aria-invalid": ariaInvalid,
|
|
@@ -2384,11 +3255,14 @@ var DOCKED_LABELS = {
|
|
|
2384
3255
|
};
|
|
2385
3256
|
function DatePickerDocked({
|
|
2386
3257
|
className,
|
|
3258
|
+
error,
|
|
3259
|
+
errorText,
|
|
2387
3260
|
labels,
|
|
2388
3261
|
locale,
|
|
2389
3262
|
max,
|
|
2390
3263
|
min,
|
|
2391
3264
|
onChange,
|
|
3265
|
+
supportingText,
|
|
2392
3266
|
value = null,
|
|
2393
3267
|
weekStartsOn
|
|
2394
3268
|
}) {
|
|
@@ -2401,6 +3275,8 @@ function DatePickerDocked({
|
|
|
2401
3275
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2402
3276
|
InputOutlined,
|
|
2403
3277
|
{
|
|
3278
|
+
error,
|
|
3279
|
+
errorText,
|
|
2404
3280
|
inputClassName: "cursor-pointer",
|
|
2405
3281
|
label: l.field,
|
|
2406
3282
|
onFocus: () => setOpen(true),
|
|
@@ -2418,6 +3294,7 @@ function DatePickerDocked({
|
|
|
2418
3294
|
children: calendarIcon
|
|
2419
3295
|
}
|
|
2420
3296
|
),
|
|
3297
|
+
supportingText,
|
|
2421
3298
|
value: formatShort(value, locale)
|
|
2422
3299
|
}
|
|
2423
3300
|
),
|
|
@@ -2425,7 +3302,7 @@ function DatePickerDocked({
|
|
|
2425
3302
|
"div",
|
|
2426
3303
|
{
|
|
2427
3304
|
"aria-label": l.field,
|
|
2428
|
-
className: "animate-menu-in absolute top-full left-0 z-
|
|
3305
|
+
className: "animate-menu-in absolute top-full left-0 z-[var(--md-sys-z-dropdown)] mt-1 w-90 max-w-[calc(100vw-2rem)] overflow-hidden rounded-large bg-surface-container-high py-2 shadow-mm-3 [--menu-clip-bleed:-24px]",
|
|
2429
3306
|
id: popupId,
|
|
2430
3307
|
role: "dialog",
|
|
2431
3308
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2574,9 +3451,14 @@ function Dropdown({
|
|
|
2574
3451
|
const [open, setOpen] = react.useState(false);
|
|
2575
3452
|
const wrapper = react.useRef(null);
|
|
2576
3453
|
const trigger = react.useRef(null);
|
|
3454
|
+
const floating = react.useRef(null);
|
|
2577
3455
|
const wasOpen = react.useRef(false);
|
|
2578
3456
|
const menuId = react.useId();
|
|
2579
3457
|
const { exiting, mounted } = useDismissable(open, 150);
|
|
3458
|
+
const pos = usePopoverPosition(wrapper, floating, mounted, {
|
|
3459
|
+
gap: apart ? 4 : 0,
|
|
3460
|
+
placement: "bottom-start"
|
|
3461
|
+
});
|
|
2580
3462
|
useOutsideClose(wrapper, () => setOpen(false), open);
|
|
2581
3463
|
const triggerNode = react.isValidElement(children) ? react.cloneElement(
|
|
2582
3464
|
children,
|
|
@@ -2607,17 +3489,29 @@ function Dropdown({
|
|
|
2607
3489
|
children: triggerNode
|
|
2608
3490
|
}
|
|
2609
3491
|
),
|
|
2610
|
-
mounted
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
3492
|
+
mounted && typeof document !== "undefined" ? reactDom.createPortal(
|
|
3493
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3494
|
+
"div",
|
|
3495
|
+
{
|
|
3496
|
+
className: "fixed z-[var(--md-sys-z-menu)]",
|
|
3497
|
+
ref: floating,
|
|
3498
|
+
style: { left: pos.left, top: pos.top },
|
|
3499
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3500
|
+
Menu,
|
|
3501
|
+
{
|
|
3502
|
+
className: menuClassName,
|
|
3503
|
+
exiting,
|
|
3504
|
+
id: menuId,
|
|
3505
|
+
onClose: () => setOpen(false),
|
|
3506
|
+
up: pos.flippedVertically,
|
|
3507
|
+
vibrant,
|
|
3508
|
+
children: menu
|
|
3509
|
+
}
|
|
3510
|
+
)
|
|
3511
|
+
}
|
|
3512
|
+
),
|
|
3513
|
+
document.body
|
|
3514
|
+
) : null
|
|
2621
3515
|
]
|
|
2622
3516
|
}
|
|
2623
3517
|
);
|
|
@@ -3000,7 +3894,7 @@ function NavigationRail({
|
|
|
3000
3894
|
"div",
|
|
3001
3895
|
{
|
|
3002
3896
|
className: cn(
|
|
3003
|
-
"fixed inset-0 z-
|
|
3897
|
+
"fixed inset-0 z-[var(--md-sys-z-modal)] bg-scrim/32",
|
|
3004
3898
|
scrim.exiting ? "animate-scrim-drawer-out" : "animate-scrim-drawer-in"
|
|
3005
3899
|
),
|
|
3006
3900
|
onClick: onClose
|
|
@@ -3025,11 +3919,16 @@ function OverflowMenu({
|
|
|
3025
3919
|
const [open, setOpen] = react.useState(false);
|
|
3026
3920
|
const wrapper = react.useRef(null);
|
|
3027
3921
|
const trigger = react.useRef(null);
|
|
3922
|
+
const floating = react.useRef(null);
|
|
3028
3923
|
const wasOpen = react.useRef(false);
|
|
3029
3924
|
const menuId = react.useId();
|
|
3030
|
-
const
|
|
3031
|
-
const opensUp = Boolean(topLeft || topRight);
|
|
3925
|
+
const placement = topRight ? "top-end" : topLeft ? "top-start" : bottomLeft ? "bottom-start" : bottomRight ? "bottom-end" : "bottom-end";
|
|
3032
3926
|
const { exiting, mounted } = useDismissable(open, 150);
|
|
3927
|
+
const pos = usePopoverPosition(wrapper, floating, mounted, {
|
|
3928
|
+
gap: 8,
|
|
3929
|
+
placement
|
|
3930
|
+
});
|
|
3931
|
+
const up = placement.startsWith("top") !== pos.flippedVertically;
|
|
3033
3932
|
useOutsideClose(wrapper, () => setOpen(false), open);
|
|
3034
3933
|
const triggerNode = react.isValidElement(children) ? react.cloneElement(
|
|
3035
3934
|
children,
|
|
@@ -3060,29 +3959,28 @@ function OverflowMenu({
|
|
|
3060
3959
|
children: triggerNode
|
|
3061
3960
|
}
|
|
3062
3961
|
),
|
|
3063
|
-
mounted
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
"
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
}
|
|
3962
|
+
mounted && typeof document !== "undefined" ? reactDom.createPortal(
|
|
3963
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3964
|
+
"div",
|
|
3965
|
+
{
|
|
3966
|
+
className: "fixed z-[var(--md-sys-z-menu)]",
|
|
3967
|
+
ref: floating,
|
|
3968
|
+
style: { left: pos.left, top: pos.top },
|
|
3969
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3970
|
+
Menu,
|
|
3971
|
+
{
|
|
3972
|
+
className: menuClassName,
|
|
3973
|
+
exiting,
|
|
3974
|
+
id: menuId,
|
|
3975
|
+
onClose: () => setOpen(false),
|
|
3976
|
+
up,
|
|
3977
|
+
vibrant,
|
|
3978
|
+
children: menu
|
|
3979
|
+
}
|
|
3980
|
+
)
|
|
3981
|
+
}
|
|
3982
|
+
),
|
|
3983
|
+
document.body
|
|
3086
3984
|
) : null
|
|
3087
3985
|
]
|
|
3088
3986
|
}
|
|
@@ -3611,17 +4509,54 @@ function SearchItem({
|
|
|
3611
4509
|
);
|
|
3612
4510
|
}
|
|
3613
4511
|
var SEARCH_INPUT_LABELS = {
|
|
4512
|
+
clear: "Clear",
|
|
3614
4513
|
placeholder: "Search"
|
|
3615
4514
|
};
|
|
4515
|
+
function CloseIcon2() {
|
|
4516
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": true, className: "h-6 w-6 fill-current", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" }) });
|
|
4517
|
+
}
|
|
3616
4518
|
function SearchInput({
|
|
3617
4519
|
className,
|
|
4520
|
+
clearable,
|
|
4521
|
+
defaultValue,
|
|
3618
4522
|
inputClassName,
|
|
3619
4523
|
labels,
|
|
3620
4524
|
leftElement,
|
|
4525
|
+
onChange,
|
|
4526
|
+
onClear,
|
|
3621
4527
|
rightElement,
|
|
4528
|
+
value: valueProp,
|
|
3622
4529
|
...inputProps
|
|
3623
4530
|
}) {
|
|
3624
4531
|
const l = { ...SEARCH_INPUT_LABELS, ...labels };
|
|
4532
|
+
const input = react.useRef(null);
|
|
4533
|
+
const [value, setValue] = useControlled(
|
|
4534
|
+
valueProp,
|
|
4535
|
+
typeof defaultValue === "string" ? defaultValue : ""
|
|
4536
|
+
);
|
|
4537
|
+
const hasValue = value.length > 0;
|
|
4538
|
+
const showClear = Boolean(
|
|
4539
|
+
clearable && hasValue && !inputProps.disabled && !rightElement
|
|
4540
|
+
);
|
|
4541
|
+
const handleChange = (event) => {
|
|
4542
|
+
setValue(event.target.value);
|
|
4543
|
+
onChange?.(event);
|
|
4544
|
+
};
|
|
4545
|
+
const clear = () => {
|
|
4546
|
+
const el = input.current;
|
|
4547
|
+
if (el) {
|
|
4548
|
+
const setter = Object.getOwnPropertyDescriptor(
|
|
4549
|
+
HTMLInputElement.prototype,
|
|
4550
|
+
"value"
|
|
4551
|
+
)?.set;
|
|
4552
|
+
setter?.call(el, "");
|
|
4553
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
4554
|
+
el.focus();
|
|
4555
|
+
} else {
|
|
4556
|
+
setValue("");
|
|
4557
|
+
}
|
|
4558
|
+
onClear?.();
|
|
4559
|
+
};
|
|
3625
4560
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative flex h-14 w-full", className), children: [
|
|
3626
4561
|
leftElement ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 flex h-14 w-14 items-center justify-center text-on-surface", children: leftElement }) : null,
|
|
3627
4562
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3631,15 +4566,29 @@ function SearchInput({
|
|
|
3631
4566
|
className: cn(
|
|
3632
4567
|
"h-14 w-full bg-transparent text-body-large text-on-surface outline-none placeholder:text-on-surface-variant",
|
|
3633
4568
|
leftElement ? "pl-14" : "pl-4",
|
|
3634
|
-
rightElement ? "pr-14" : "pr-4",
|
|
4569
|
+
rightElement || showClear ? "pr-14" : "pr-4",
|
|
4570
|
+
// Hide the inconsistent native clear when we render our own.
|
|
4571
|
+
showClear && "[&::-webkit-search-cancel-button]:hidden",
|
|
3635
4572
|
inputClassName
|
|
3636
4573
|
),
|
|
3637
4574
|
type: "search",
|
|
3638
4575
|
...inputProps,
|
|
3639
|
-
|
|
4576
|
+
onChange: handleChange,
|
|
4577
|
+
placeholder: l.placeholder,
|
|
4578
|
+
ref: input,
|
|
4579
|
+
value
|
|
3640
4580
|
}
|
|
3641
4581
|
),
|
|
3642
|
-
rightElement ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 flex h-14 w-14 items-center justify-center text-on-surface-variant", children: rightElement }) :
|
|
4582
|
+
rightElement ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 flex h-14 w-14 items-center justify-center text-on-surface-variant", children: rightElement }) : showClear ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 flex h-14 w-14 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4583
|
+
"button",
|
|
4584
|
+
{
|
|
4585
|
+
"aria-label": l.clear,
|
|
4586
|
+
className: "state-layer flex h-12 w-12 cursor-pointer items-center justify-center rounded-full text-on-surface-variant",
|
|
4587
|
+
onClick: clear,
|
|
4588
|
+
type: "button",
|
|
4589
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon2, {})
|
|
4590
|
+
}
|
|
4591
|
+
) }) : null
|
|
3643
4592
|
] });
|
|
3644
4593
|
}
|
|
3645
4594
|
function Search({
|
|
@@ -3658,7 +4607,7 @@ function Search({
|
|
|
3658
4607
|
"div",
|
|
3659
4608
|
{
|
|
3660
4609
|
className: cn(
|
|
3661
|
-
"relative z-
|
|
4610
|
+
"relative z-[var(--md-sys-z-dropdown)] flex h-fit w-full min-w-[360px] max-w-[720px] cursor-pointer bg-surface-container-high text-on-surface",
|
|
3662
4611
|
// Contained (M3 Expressive): the bar stays a persistent 28px
|
|
3663
4612
|
// pill (real px — corner-full would snap instead of morphing).
|
|
3664
4613
|
// Divided (baseline): its bottom corners square off in step
|
|
@@ -3709,221 +4658,6 @@ function Search({
|
|
|
3709
4658
|
}
|
|
3710
4659
|
Search.Item = SearchItem;
|
|
3711
4660
|
Search.Input = SearchInput;
|
|
3712
|
-
function useControlled(controlled, defaultValue) {
|
|
3713
|
-
const isControlled = react.useRef(controlled !== void 0).current;
|
|
3714
|
-
const [internal, setInternal] = react.useState(defaultValue);
|
|
3715
|
-
const value = isControlled && controlled !== void 0 ? controlled : internal;
|
|
3716
|
-
const setValue = react.useCallback(
|
|
3717
|
-
(next) => {
|
|
3718
|
-
if (!isControlled) setInternal(next);
|
|
3719
|
-
},
|
|
3720
|
-
[isControlled]
|
|
3721
|
-
);
|
|
3722
|
-
return [value, setValue];
|
|
3723
|
-
}
|
|
3724
|
-
var TYPEAHEAD_BUFFER_MS = 200;
|
|
3725
|
-
function optionText(option) {
|
|
3726
|
-
return typeof option.label === "string" ? option.label : option.value;
|
|
3727
|
-
}
|
|
3728
|
-
function useSelect({
|
|
3729
|
-
defaultValue,
|
|
3730
|
-
disabled,
|
|
3731
|
-
onChange,
|
|
3732
|
-
options,
|
|
3733
|
-
value: valueProp
|
|
3734
|
-
}) {
|
|
3735
|
-
const [value, setValue] = useControlled(valueProp, defaultValue ?? "");
|
|
3736
|
-
const [isOpen, setIsOpen] = react.useState(false);
|
|
3737
|
-
const [focused, setFocused] = react.useState(false);
|
|
3738
|
-
const [highlighted, setHighlighted] = react.useState(-1);
|
|
3739
|
-
const wrapper = react.useRef(null);
|
|
3740
|
-
const typeahead = react.useRef({ buffer: "", time: 0 });
|
|
3741
|
-
const { exiting, mounted } = useDismissable(isOpen, 150);
|
|
3742
|
-
useOutsideClose(wrapper, () => setIsOpen(false), isOpen);
|
|
3743
|
-
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
3744
|
-
const move = (start, delta) => {
|
|
3745
|
-
for (let step = 1; step <= options.length; step += 1) {
|
|
3746
|
-
const index = (start + delta * step + options.length * step) % options.length;
|
|
3747
|
-
if (!options[index]?.disabled) return index;
|
|
3748
|
-
}
|
|
3749
|
-
return -1;
|
|
3750
|
-
};
|
|
3751
|
-
const openMenu = () => {
|
|
3752
|
-
if (disabled) return;
|
|
3753
|
-
setHighlighted(
|
|
3754
|
-
selectedIndex >= 0 && !options[selectedIndex]?.disabled ? selectedIndex : move(-1, 1)
|
|
3755
|
-
);
|
|
3756
|
-
setIsOpen(true);
|
|
3757
|
-
};
|
|
3758
|
-
const commit = (next) => {
|
|
3759
|
-
setValue(next);
|
|
3760
|
-
onChange?.(next);
|
|
3761
|
-
setIsOpen(false);
|
|
3762
|
-
};
|
|
3763
|
-
const typeaheadFind = (char) => {
|
|
3764
|
-
const now = Date.now();
|
|
3765
|
-
const stale = now - typeahead.current.time > TYPEAHEAD_BUFFER_MS;
|
|
3766
|
-
typeahead.current = {
|
|
3767
|
-
buffer: (stale ? "" : typeahead.current.buffer) + char.toLowerCase(),
|
|
3768
|
-
time: now
|
|
3769
|
-
};
|
|
3770
|
-
return options.findIndex(
|
|
3771
|
-
(option) => !option.disabled && optionText(option).toLowerCase().startsWith(typeahead.current.buffer)
|
|
3772
|
-
);
|
|
3773
|
-
};
|
|
3774
|
-
const handleKeyDown = (event) => {
|
|
3775
|
-
if (disabled) return;
|
|
3776
|
-
const { key } = event;
|
|
3777
|
-
const printable = key.length === 1 && key !== " " && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
3778
|
-
if (!isOpen) {
|
|
3779
|
-
if (["ArrowDown", "ArrowUp", "Enter", " "].includes(key)) {
|
|
3780
|
-
event.preventDefault();
|
|
3781
|
-
openMenu();
|
|
3782
|
-
} else if (printable) {
|
|
3783
|
-
const index = typeaheadFind(key);
|
|
3784
|
-
if (index >= 0) {
|
|
3785
|
-
setValue(options[index].value);
|
|
3786
|
-
onChange?.(options[index].value);
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
return;
|
|
3790
|
-
}
|
|
3791
|
-
switch (key) {
|
|
3792
|
-
case "ArrowDown":
|
|
3793
|
-
event.preventDefault();
|
|
3794
|
-
setHighlighted((current) => move(current, 1));
|
|
3795
|
-
break;
|
|
3796
|
-
case "ArrowUp":
|
|
3797
|
-
event.preventDefault();
|
|
3798
|
-
setHighlighted((current) => move(current, -1));
|
|
3799
|
-
break;
|
|
3800
|
-
case "Home":
|
|
3801
|
-
event.preventDefault();
|
|
3802
|
-
setHighlighted(move(-1, 1));
|
|
3803
|
-
break;
|
|
3804
|
-
case "End":
|
|
3805
|
-
event.preventDefault();
|
|
3806
|
-
setHighlighted(move(options.length, -1));
|
|
3807
|
-
break;
|
|
3808
|
-
case "Enter":
|
|
3809
|
-
case " ": {
|
|
3810
|
-
event.preventDefault();
|
|
3811
|
-
const option = options[highlighted];
|
|
3812
|
-
if (option && !option.disabled) commit(option.value);
|
|
3813
|
-
break;
|
|
3814
|
-
}
|
|
3815
|
-
case "Escape":
|
|
3816
|
-
event.preventDefault();
|
|
3817
|
-
setIsOpen(false);
|
|
3818
|
-
break;
|
|
3819
|
-
case "Tab":
|
|
3820
|
-
setIsOpen(false);
|
|
3821
|
-
break;
|
|
3822
|
-
default:
|
|
3823
|
-
if (printable) {
|
|
3824
|
-
const index = typeaheadFind(key);
|
|
3825
|
-
if (index >= 0) setHighlighted(index);
|
|
3826
|
-
}
|
|
3827
|
-
}
|
|
3828
|
-
};
|
|
3829
|
-
return {
|
|
3830
|
-
commit,
|
|
3831
|
-
exiting,
|
|
3832
|
-
focused: focused && !disabled,
|
|
3833
|
-
handleKeyDown,
|
|
3834
|
-
highlighted,
|
|
3835
|
-
isOpen,
|
|
3836
|
-
mounted,
|
|
3837
|
-
openMenu,
|
|
3838
|
-
selectedIndex,
|
|
3839
|
-
setFocused,
|
|
3840
|
-
setHighlighted,
|
|
3841
|
-
setIsOpen,
|
|
3842
|
-
value,
|
|
3843
|
-
wrapper
|
|
3844
|
-
};
|
|
3845
|
-
}
|
|
3846
|
-
function SelectMenu({
|
|
3847
|
-
baseId,
|
|
3848
|
-
exiting,
|
|
3849
|
-
highlighted,
|
|
3850
|
-
onHighlight,
|
|
3851
|
-
onSelect,
|
|
3852
|
-
options,
|
|
3853
|
-
value
|
|
3854
|
-
}) {
|
|
3855
|
-
react.useEffect(() => {
|
|
3856
|
-
if (highlighted < 0) return;
|
|
3857
|
-
document.getElementById(`${baseId}-opt-${highlighted}`)?.scrollIntoView({ block: "nearest" });
|
|
3858
|
-
}, [baseId, highlighted]);
|
|
3859
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3860
|
-
"ul",
|
|
3861
|
-
{
|
|
3862
|
-
className: cn(
|
|
3863
|
-
"absolute top-full left-0 z-30 mt-1 flex max-h-[280px] w-full min-w-max flex-col overflow-hidden overflow-y-auto rounded-large bg-surface-container-low py-0.5 shadow-mm-3 [--menu-clip-bleed:-24px]",
|
|
3864
|
-
exiting ? "animate-menu-out" : "animate-menu-in"
|
|
3865
|
-
),
|
|
3866
|
-
id: `${baseId}-listbox`,
|
|
3867
|
-
role: "listbox",
|
|
3868
|
-
children: options.map((option, index) => {
|
|
3869
|
-
const isSelected = option.value === value;
|
|
3870
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3871
|
-
"li",
|
|
3872
|
-
{
|
|
3873
|
-
"aria-disabled": option.disabled || void 0,
|
|
3874
|
-
"aria-selected": isSelected,
|
|
3875
|
-
className: cn(
|
|
3876
|
-
"mx-1 my-0.5 flex h-11 shrink-0 cursor-pointer items-center rounded-extra-small px-3 text-label-large first:rounded-t-medium last:rounded-b-medium",
|
|
3877
|
-
isSelected ? "rounded-medium bg-tertiary-container text-on-tertiary-container" : "text-on-surface",
|
|
3878
|
-
highlighted === index && !isSelected && "bg-on-surface/8",
|
|
3879
|
-
option.disabled && "cursor-not-allowed text-on-surface/38"
|
|
3880
|
-
),
|
|
3881
|
-
id: `${baseId}-opt-${index}`,
|
|
3882
|
-
onClick: () => {
|
|
3883
|
-
if (!option.disabled) onSelect(option.value);
|
|
3884
|
-
},
|
|
3885
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
3886
|
-
onMouseEnter: () => {
|
|
3887
|
-
if (!option.disabled) onHighlight(index);
|
|
3888
|
-
},
|
|
3889
|
-
role: "option",
|
|
3890
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: option.label ?? option.value })
|
|
3891
|
-
},
|
|
3892
|
-
option.value
|
|
3893
|
-
);
|
|
3894
|
-
})
|
|
3895
|
-
}
|
|
3896
|
-
);
|
|
3897
|
-
}
|
|
3898
|
-
function SelectCaret({ open = false }) {
|
|
3899
|
-
const fade = "ease-md-linear transition-opacity delay-75 duration-75";
|
|
3900
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3901
|
-
"svg",
|
|
3902
|
-
{
|
|
3903
|
-
"aria-hidden": true,
|
|
3904
|
-
fill: "currentColor",
|
|
3905
|
-
height: 24,
|
|
3906
|
-
viewBox: "0 0 24 24",
|
|
3907
|
-
width: 24,
|
|
3908
|
-
children: [
|
|
3909
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3910
|
-
"path",
|
|
3911
|
-
{
|
|
3912
|
-
className: cn(fade, open ? "opacity-0" : "opacity-100"),
|
|
3913
|
-
d: "M7 10l5 5 5-5z"
|
|
3914
|
-
}
|
|
3915
|
-
),
|
|
3916
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3917
|
-
"path",
|
|
3918
|
-
{
|
|
3919
|
-
className: cn(fade, open ? "opacity-100" : "opacity-0"),
|
|
3920
|
-
d: "M7 15l5-5 5 5z"
|
|
3921
|
-
}
|
|
3922
|
-
)
|
|
3923
|
-
]
|
|
3924
|
-
}
|
|
3925
|
-
);
|
|
3926
|
-
}
|
|
3927
4661
|
function SelectFilled({
|
|
3928
4662
|
className,
|
|
3929
4663
|
defaultValue,
|
|
@@ -4252,7 +4986,7 @@ function BottomSheet({
|
|
|
4252
4986
|
"div",
|
|
4253
4987
|
{
|
|
4254
4988
|
className: cn(
|
|
4255
|
-
"fixed inset-0 z-
|
|
4989
|
+
"fixed inset-0 z-[var(--md-sys-z-modal)] flex items-end justify-center bg-scrim/32",
|
|
4256
4990
|
exiting ? "animate-scrim-sheet-out" : "animate-scrim-sheet-in"
|
|
4257
4991
|
),
|
|
4258
4992
|
onClick: onClose,
|
|
@@ -4294,7 +5028,7 @@ var SIDE_SHEET_LABELS = {
|
|
|
4294
5028
|
close: "Close",
|
|
4295
5029
|
label: "Side sheet"
|
|
4296
5030
|
};
|
|
4297
|
-
function
|
|
5031
|
+
function CloseIcon3() {
|
|
4298
5032
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": true, fill: "none", height: 24, viewBox: "0 0 24 24", width: 24, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4299
5033
|
"path",
|
|
4300
5034
|
{
|
|
@@ -4340,7 +5074,7 @@ function SideSheet({
|
|
|
4340
5074
|
"div",
|
|
4341
5075
|
{
|
|
4342
5076
|
className: cn(
|
|
4343
|
-
"fixed inset-0 z-
|
|
5077
|
+
"fixed inset-0 z-[var(--md-sys-z-modal)] flex justify-end bg-scrim/32",
|
|
4344
5078
|
exiting ? "animate-scrim-sheet-out" : "animate-scrim-sheet-in"
|
|
4345
5079
|
),
|
|
4346
5080
|
onClick: onClose,
|
|
@@ -4374,7 +5108,7 @@ function SideSheet({
|
|
|
4374
5108
|
IconButton,
|
|
4375
5109
|
{
|
|
4376
5110
|
"aria-label": l.close,
|
|
4377
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5111
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon3, {}),
|
|
4378
5112
|
onClick: onClose,
|
|
4379
5113
|
variant: "standard"
|
|
4380
5114
|
}
|
|
@@ -4771,7 +5505,7 @@ function SliderDual({
|
|
|
4771
5505
|
);
|
|
4772
5506
|
}
|
|
4773
5507
|
var SNACKBAR_LABELS = { dismiss: "Dismiss" };
|
|
4774
|
-
function
|
|
5508
|
+
function CloseIcon4() {
|
|
4775
5509
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": true, fill: "none", height: 24, viewBox: "0 0 24 24", width: 24, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4776
5510
|
"path",
|
|
4777
5511
|
{
|
|
@@ -4850,7 +5584,7 @@ function Snackbar({
|
|
|
4850
5584
|
className: "iconBtn standard text-inverse-on-surface",
|
|
4851
5585
|
onClick: onClose,
|
|
4852
5586
|
type: "button",
|
|
4853
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-6 w-6 items-center justify-center leading-none", children: closeIcon ?? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5587
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-6 w-6 items-center justify-center leading-none", children: closeIcon ?? /* @__PURE__ */ jsxRuntime.jsx(CloseIcon4, {}) })
|
|
4854
5588
|
}
|
|
4855
5589
|
) : null
|
|
4856
5590
|
] })
|
|
@@ -4864,7 +5598,7 @@ function SnackbarWrapper({ children, className }) {
|
|
|
4864
5598
|
react.useEffect(() => setMounted(true), []);
|
|
4865
5599
|
if (!mounted) return null;
|
|
4866
5600
|
return reactDom.createPortal(
|
|
4867
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none fixed inset-x-4 top-auto bottom-0 z-
|
|
5601
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none fixed inset-x-4 top-auto bottom-0 z-[var(--md-sys-z-snackbar)] flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4868
5602
|
"div",
|
|
4869
5603
|
{
|
|
4870
5604
|
className: cn(
|
|
@@ -6177,7 +6911,7 @@ function Tooltip({
|
|
|
6177
6911
|
{
|
|
6178
6912
|
id: tooltipId,
|
|
6179
6913
|
className: cn(
|
|
6180
|
-
"tooltip absolute z-
|
|
6914
|
+
"tooltip absolute z-[var(--md-sys-z-tooltip)] my-1",
|
|
6181
6915
|
rich ? "pointer-events-none w-max max-w-[320px] rounded-medium bg-surface-container px-4 pt-3 pb-2 shadow-mm-2 group-hover:pointer-events-auto group-focus-within:pointer-events-auto" : "pointer-events-none max-w-[200px] rounded-extra-small bg-inverse-surface px-2 py-1",
|
|
6182
6916
|
topRight && "right-0 bottom-full",
|
|
6183
6917
|
topLeft && "bottom-full left-0",
|
|
@@ -6869,40 +7603,54 @@ function Switch({
|
|
|
6869
7603
|
);
|
|
6870
7604
|
}
|
|
6871
7605
|
function TextElement({
|
|
7606
|
+
as: Wrapper = "div",
|
|
6872
7607
|
body,
|
|
7608
|
+
bodyAs: Body = "p",
|
|
6873
7609
|
bodyStyle,
|
|
6874
7610
|
className,
|
|
6875
7611
|
label,
|
|
7612
|
+
labelAs: Label = "p",
|
|
6876
7613
|
labelStyle,
|
|
6877
7614
|
title,
|
|
7615
|
+
titleAs: Title = "h2",
|
|
6878
7616
|
titleStyle
|
|
6879
7617
|
}) {
|
|
7618
|
+
const bare = [label, title, body].filter(Boolean).length === 1;
|
|
7619
|
+
const labelNode = label ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7620
|
+
Label,
|
|
7621
|
+
{
|
|
7622
|
+
className: cn(
|
|
7623
|
+
"text-label-medium text-on-surface-variant",
|
|
7624
|
+
labelStyle,
|
|
7625
|
+
bare && className
|
|
7626
|
+
),
|
|
7627
|
+
children: label
|
|
7628
|
+
}
|
|
7629
|
+
) : null;
|
|
7630
|
+
const titleNode = title ? /* @__PURE__ */ jsxRuntime.jsx(Title, { className: cn("text-title-medium text-on-surface", titleStyle, bare && className), children: title }) : null;
|
|
7631
|
+
const bodyNode = body ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7632
|
+
Body,
|
|
7633
|
+
{
|
|
7634
|
+
className: cn(
|
|
7635
|
+
"text-body-medium text-on-surface-variant",
|
|
7636
|
+
bodyStyle,
|
|
7637
|
+
bare && className
|
|
7638
|
+
),
|
|
7639
|
+
children: body
|
|
7640
|
+
}
|
|
7641
|
+
) : null;
|
|
7642
|
+
if (bare) return labelNode ?? titleNode ?? bodyNode;
|
|
6880
7643
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6881
|
-
|
|
7644
|
+
Wrapper,
|
|
6882
7645
|
{
|
|
6883
7646
|
className: cn(
|
|
6884
7647
|
"flex flex-col items-start justify-center text-on-surface",
|
|
6885
7648
|
className
|
|
6886
7649
|
),
|
|
6887
7650
|
children: [
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
className: cn(
|
|
6892
|
-
"text-label-medium text-on-surface-variant",
|
|
6893
|
-
labelStyle
|
|
6894
|
-
),
|
|
6895
|
-
children: label
|
|
6896
|
-
}
|
|
6897
|
-
) : null,
|
|
6898
|
-
title ? /* @__PURE__ */ jsxRuntime.jsx("h2", { className: cn("text-title-medium", titleStyle), children: title }) : null,
|
|
6899
|
-
body ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6900
|
-
"p",
|
|
6901
|
-
{
|
|
6902
|
-
className: cn("text-body-medium text-on-surface-variant", bodyStyle),
|
|
6903
|
-
children: body
|
|
6904
|
-
}
|
|
6905
|
-
) : null
|
|
7651
|
+
labelNode,
|
|
7652
|
+
titleNode,
|
|
7653
|
+
bodyNode
|
|
6906
7654
|
]
|
|
6907
7655
|
}
|
|
6908
7656
|
);
|
|
@@ -6951,6 +7699,8 @@ exports.Card = Card;
|
|
|
6951
7699
|
exports.Checkbox = Checkbox;
|
|
6952
7700
|
exports.Chips = Chips;
|
|
6953
7701
|
exports.Circle = Circle;
|
|
7702
|
+
exports.ComboboxFilled = ComboboxFilled;
|
|
7703
|
+
exports.ComboboxOutlined = ComboboxOutlined;
|
|
6954
7704
|
exports.Container = Container;
|
|
6955
7705
|
exports.DatePicker = DatePicker;
|
|
6956
7706
|
exports.DateRangePicker = DateRangePicker;
|