@tinybigui/react 0.2.0 → 0.3.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/dist/index.cjs +1662 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +53 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +1539 -12
- package/dist/index.d.ts +1539 -12
- package/dist/index.js +1639 -4
- package/dist/index.js.map +1 -1
- package/dist/styles.css +84 -2
- package/dist/styles.css.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,15 +1,49 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
|
-
import {
|
|
2
|
+
import { extendTailwindMerge } from 'tailwind-merge';
|
|
3
3
|
import { argbFromHex, themeFromSourceColor } from '@material/material-color-utilities';
|
|
4
4
|
export { argbFromHex, hexFromArgb } from '@material/material-color-utilities';
|
|
5
|
-
import { forwardRef, useRef, useEffect, createContext, useContext, useMemo, useCallback, useState, useLayoutEffect, Children, isValidElement } from 'react';
|
|
5
|
+
import { forwardRef, useRef, useEffect, createContext, useContext, useMemo, useCallback, useState, useLayoutEffect, useId, Children, isValidElement, cloneElement } from 'react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
import { cva } from 'class-variance-authority';
|
|
8
|
-
import { useButton, useTextField, useFocusRing, useCheckbox, VisuallyHidden, mergeProps as mergeProps$1, useSwitch, useRadioGroup, useRadio, useTabList, useTab, useTabPanel, FocusScope, usePreventScroll, useDialog, useOverlay, useLink } from 'react-aria';
|
|
8
|
+
import { useButton, useTextField, useFocusRing, useCheckbox, VisuallyHidden, mergeProps as mergeProps$1, useSwitch, useRadioGroup, useRadio, useTabList, useTab, useTabPanel, FocusScope, usePreventScroll, useDialog, useOverlay, useLink, useProgressBar } from 'react-aria';
|
|
9
9
|
import { mergeProps, filterDOMProps } from '@react-aria/utils';
|
|
10
10
|
import { useToggleState, useRadioGroupState, useTabListState, Item, useOverlayTriggerState } from 'react-stately';
|
|
11
|
+
import { MenuItem as MenuItem$1, Menu as Menu$1, MenuTrigger as MenuTrigger$1, Popover, MenuSection as MenuSection$1, Separator, Header, useSlottedContext, ButtonContext } from 'react-aria-components';
|
|
12
|
+
import { createPortal } from 'react-dom';
|
|
11
13
|
|
|
12
14
|
// src/utils/cn.ts
|
|
15
|
+
var twMerge = extendTailwindMerge({
|
|
16
|
+
extend: {
|
|
17
|
+
classGroups: {
|
|
18
|
+
"font-size": [
|
|
19
|
+
{
|
|
20
|
+
text: [
|
|
21
|
+
// MD3 Display scale
|
|
22
|
+
"display-large",
|
|
23
|
+
"display-medium",
|
|
24
|
+
"display-small",
|
|
25
|
+
// MD3 Headline scale
|
|
26
|
+
"headline-large",
|
|
27
|
+
"headline-medium",
|
|
28
|
+
"headline-small",
|
|
29
|
+
// MD3 Title scale
|
|
30
|
+
"title-large",
|
|
31
|
+
"title-medium",
|
|
32
|
+
"title-small",
|
|
33
|
+
// MD3 Body scale
|
|
34
|
+
"body-large",
|
|
35
|
+
"body-medium",
|
|
36
|
+
"body-small",
|
|
37
|
+
// MD3 Label scale
|
|
38
|
+
"label-large",
|
|
39
|
+
"label-medium",
|
|
40
|
+
"label-small"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
13
47
|
function cn(...inputs) {
|
|
14
48
|
return twMerge(clsx(inputs));
|
|
15
49
|
}
|
|
@@ -4498,7 +4532,1608 @@ var DrawerSection = forwardRef(
|
|
|
4498
4532
|
}
|
|
4499
4533
|
);
|
|
4500
4534
|
DrawerSection.displayName = "DrawerSection";
|
|
4535
|
+
var progressContainerVariants = cva(["inline-flex", "flex-col", "gap-1"], {
|
|
4536
|
+
variants: {
|
|
4537
|
+
/**
|
|
4538
|
+
* The visual type of the indicator.
|
|
4539
|
+
*/
|
|
4540
|
+
type: {
|
|
4541
|
+
linear: "w-full",
|
|
4542
|
+
circular: "items-center justify-center w-auto"
|
|
4543
|
+
}
|
|
4544
|
+
},
|
|
4545
|
+
defaultVariants: {
|
|
4546
|
+
type: "linear"
|
|
4547
|
+
}
|
|
4548
|
+
});
|
|
4549
|
+
var progressTrackVariants = cva([
|
|
4550
|
+
"relative",
|
|
4551
|
+
"w-full",
|
|
4552
|
+
"h-1",
|
|
4553
|
+
// MD3: 4dp track height
|
|
4554
|
+
"rounded-full",
|
|
4555
|
+
// MD3: full corner radius
|
|
4556
|
+
"overflow-hidden",
|
|
4557
|
+
"bg-surface-container-highest"
|
|
4558
|
+
// MD3: inactive track color
|
|
4559
|
+
]);
|
|
4560
|
+
var progressIndicatorVariants = cva([
|
|
4561
|
+
"absolute",
|
|
4562
|
+
"left-0",
|
|
4563
|
+
"top-0",
|
|
4564
|
+
"h-full",
|
|
4565
|
+
"rounded-full",
|
|
4566
|
+
"bg-primary",
|
|
4567
|
+
// MD3: active track color
|
|
4568
|
+
"transition-[width]",
|
|
4569
|
+
"duration-medium4",
|
|
4570
|
+
// MD3: 400ms for value transitions
|
|
4571
|
+
"ease-standard"
|
|
4572
|
+
// MD3: cubic-bezier(0.2, 0, 0, 1)
|
|
4573
|
+
]);
|
|
4574
|
+
var progressStopIndicatorVariants = cva([
|
|
4575
|
+
"absolute",
|
|
4576
|
+
"right-0",
|
|
4577
|
+
"top-1/2",
|
|
4578
|
+
"-translate-y-1/2",
|
|
4579
|
+
"w-1",
|
|
4580
|
+
"h-1",
|
|
4581
|
+
"rounded-full",
|
|
4582
|
+
"bg-primary"
|
|
4583
|
+
// MD3: stop indicator uses primary color
|
|
4584
|
+
]);
|
|
4585
|
+
var progressCircularSizeVariants = cva(
|
|
4586
|
+
["relative", "flex", "items-center", "justify-center", "flex-shrink-0"],
|
|
4587
|
+
{
|
|
4588
|
+
variants: {
|
|
4589
|
+
size: {
|
|
4590
|
+
small: "h-6 w-6",
|
|
4591
|
+
// MD3: 24dp
|
|
4592
|
+
medium: "h-12 w-12",
|
|
4593
|
+
// MD3: 48dp (default)
|
|
4594
|
+
large: "h-16 w-16"
|
|
4595
|
+
// MD3: 64dp
|
|
4596
|
+
}
|
|
4597
|
+
},
|
|
4598
|
+
defaultVariants: {
|
|
4599
|
+
size: "medium"
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
);
|
|
4603
|
+
var progressLabelVariants = cva([
|
|
4604
|
+
"text-body-small",
|
|
4605
|
+
// MD3: body-small type scale (12px)
|
|
4606
|
+
"text-on-surface",
|
|
4607
|
+
// MD3: on-surface color role
|
|
4608
|
+
"select-none"
|
|
4609
|
+
]);
|
|
4610
|
+
var STROKE_WIDTH = 4;
|
|
4611
|
+
var CIRCULAR_SIZE_PX = {
|
|
4612
|
+
small: 24,
|
|
4613
|
+
medium: 48,
|
|
4614
|
+
large: 64
|
|
4615
|
+
};
|
|
4616
|
+
function getCircularGeometry(size) {
|
|
4617
|
+
const diameter = CIRCULAR_SIZE_PX[size];
|
|
4618
|
+
const radius = (diameter - STROKE_WIDTH) / 2;
|
|
4619
|
+
const circumference = 2 * Math.PI * radius;
|
|
4620
|
+
const viewBox = `0 0 ${diameter} ${diameter}`;
|
|
4621
|
+
const cx = diameter / 2;
|
|
4622
|
+
const cy = diameter / 2;
|
|
4623
|
+
return { diameter, radius, circumference, viewBox, cx, cy };
|
|
4624
|
+
}
|
|
4625
|
+
var Progress = forwardRef(
|
|
4626
|
+
({
|
|
4627
|
+
type = "linear",
|
|
4628
|
+
indeterminate = false,
|
|
4629
|
+
size = "medium",
|
|
4630
|
+
className,
|
|
4631
|
+
label,
|
|
4632
|
+
value = 0,
|
|
4633
|
+
minValue = 0,
|
|
4634
|
+
maxValue = 100,
|
|
4635
|
+
...restProps
|
|
4636
|
+
}, forwardedRef) => {
|
|
4637
|
+
const internalRef = useRef(null);
|
|
4638
|
+
const ref = forwardedRef ?? internalRef;
|
|
4639
|
+
const { progressBarProps, labelProps } = useProgressBar({
|
|
4640
|
+
label,
|
|
4641
|
+
value,
|
|
4642
|
+
minValue,
|
|
4643
|
+
maxValue,
|
|
4644
|
+
isIndeterminate: indeterminate,
|
|
4645
|
+
...restProps
|
|
4646
|
+
});
|
|
4647
|
+
const percentage = indeterminate ? 0 : Math.min(100, Math.max(0, (value - minValue) / (maxValue - minValue) * 100));
|
|
4648
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4649
|
+
const ariaProps = restProps;
|
|
4650
|
+
if (!label && !ariaProps["aria-label"] && !ariaProps["aria-labelledby"]) {
|
|
4651
|
+
console.warn(
|
|
4652
|
+
"[Progress] Progress indicator should have a visible label prop or aria-label for accessibility."
|
|
4653
|
+
);
|
|
4654
|
+
}
|
|
4655
|
+
}
|
|
4656
|
+
return /* @__PURE__ */ jsxs(
|
|
4657
|
+
"div",
|
|
4658
|
+
{
|
|
4659
|
+
...progressBarProps,
|
|
4660
|
+
ref,
|
|
4661
|
+
className: cn(progressContainerVariants({ type }), className),
|
|
4662
|
+
children: [
|
|
4663
|
+
label && /* @__PURE__ */ jsx("span", { ...labelProps, className: cn(progressLabelVariants()), children: label }),
|
|
4664
|
+
type === "linear" ? /* @__PURE__ */ jsx(LinearProgress, { percentage, indeterminate }) : /* @__PURE__ */ jsx(CircularProgress, { percentage, indeterminate, size })
|
|
4665
|
+
]
|
|
4666
|
+
}
|
|
4667
|
+
);
|
|
4668
|
+
}
|
|
4669
|
+
);
|
|
4670
|
+
Progress.displayName = "Progress";
|
|
4671
|
+
function LinearProgress({ percentage, indeterminate }) {
|
|
4672
|
+
if (indeterminate) {
|
|
4673
|
+
return /* @__PURE__ */ jsx("div", { "data-progress-track": "", className: cn(progressTrackVariants()), children: /* @__PURE__ */ jsxs(
|
|
4674
|
+
"div",
|
|
4675
|
+
{
|
|
4676
|
+
"data-progress-indeterminate": "",
|
|
4677
|
+
className: "absolute inset-0 overflow-hidden rounded-full",
|
|
4678
|
+
children: [
|
|
4679
|
+
/* @__PURE__ */ jsx(
|
|
4680
|
+
"div",
|
|
4681
|
+
{
|
|
4682
|
+
className: cn(
|
|
4683
|
+
"bg-primary absolute top-0 h-full rounded-full",
|
|
4684
|
+
"animate-progress-linear-indeterminate-1"
|
|
4685
|
+
)
|
|
4686
|
+
}
|
|
4687
|
+
),
|
|
4688
|
+
/* @__PURE__ */ jsx(
|
|
4689
|
+
"div",
|
|
4690
|
+
{
|
|
4691
|
+
className: cn(
|
|
4692
|
+
"bg-primary absolute top-0 h-full rounded-full",
|
|
4693
|
+
"animate-progress-linear-indeterminate-2"
|
|
4694
|
+
)
|
|
4695
|
+
}
|
|
4696
|
+
)
|
|
4697
|
+
]
|
|
4698
|
+
}
|
|
4699
|
+
) });
|
|
4700
|
+
}
|
|
4701
|
+
return /* @__PURE__ */ jsxs("div", { "data-progress-track": "", className: cn(progressTrackVariants()), children: [
|
|
4702
|
+
/* @__PURE__ */ jsx(
|
|
4703
|
+
"div",
|
|
4704
|
+
{
|
|
4705
|
+
"data-progress-indicator": "",
|
|
4706
|
+
className: cn(progressIndicatorVariants()),
|
|
4707
|
+
style: { width: `${percentage}%` }
|
|
4708
|
+
}
|
|
4709
|
+
),
|
|
4710
|
+
/* @__PURE__ */ jsx(
|
|
4711
|
+
"div",
|
|
4712
|
+
{
|
|
4713
|
+
"data-stop-indicator": "",
|
|
4714
|
+
className: cn(progressStopIndicatorVariants()),
|
|
4715
|
+
"aria-hidden": "true"
|
|
4716
|
+
}
|
|
4717
|
+
)
|
|
4718
|
+
] });
|
|
4719
|
+
}
|
|
4720
|
+
function CircularProgress({
|
|
4721
|
+
percentage,
|
|
4722
|
+
indeterminate,
|
|
4723
|
+
size
|
|
4724
|
+
}) {
|
|
4725
|
+
const { radius, circumference, viewBox, cx, cy } = getCircularGeometry(size);
|
|
4726
|
+
const strokeDashoffset = (1 - percentage / 100) * circumference;
|
|
4727
|
+
if (indeterminate) {
|
|
4728
|
+
return /* @__PURE__ */ jsx(
|
|
4729
|
+
"div",
|
|
4730
|
+
{
|
|
4731
|
+
"data-progress-size": size,
|
|
4732
|
+
"data-progress-indeterminate": "",
|
|
4733
|
+
className: cn(progressCircularSizeVariants({ size })),
|
|
4734
|
+
children: /* @__PURE__ */ jsxs(
|
|
4735
|
+
"svg",
|
|
4736
|
+
{
|
|
4737
|
+
viewBox,
|
|
4738
|
+
className: "animate-progress-circular-rotate h-full w-full",
|
|
4739
|
+
"aria-hidden": "true",
|
|
4740
|
+
children: [
|
|
4741
|
+
/* @__PURE__ */ jsx(
|
|
4742
|
+
"circle",
|
|
4743
|
+
{
|
|
4744
|
+
cx,
|
|
4745
|
+
cy,
|
|
4746
|
+
r: radius,
|
|
4747
|
+
fill: "none",
|
|
4748
|
+
stroke: "currentColor",
|
|
4749
|
+
strokeWidth: STROKE_WIDTH,
|
|
4750
|
+
className: "text-surface-container-highest"
|
|
4751
|
+
}
|
|
4752
|
+
),
|
|
4753
|
+
/* @__PURE__ */ jsx(
|
|
4754
|
+
"circle",
|
|
4755
|
+
{
|
|
4756
|
+
cx,
|
|
4757
|
+
cy,
|
|
4758
|
+
r: radius,
|
|
4759
|
+
fill: "none",
|
|
4760
|
+
stroke: "currentColor",
|
|
4761
|
+
strokeWidth: STROKE_WIDTH,
|
|
4762
|
+
className: "animate-progress-circular-dash text-primary",
|
|
4763
|
+
strokeLinecap: "round"
|
|
4764
|
+
}
|
|
4765
|
+
)
|
|
4766
|
+
]
|
|
4767
|
+
}
|
|
4768
|
+
)
|
|
4769
|
+
}
|
|
4770
|
+
);
|
|
4771
|
+
}
|
|
4772
|
+
return /* @__PURE__ */ jsx("div", { "data-progress-size": size, className: cn(progressCircularSizeVariants({ size })), children: /* @__PURE__ */ jsxs("svg", { viewBox, className: "h-full w-full -rotate-90", "aria-hidden": "true", children: [
|
|
4773
|
+
/* @__PURE__ */ jsx(
|
|
4774
|
+
"circle",
|
|
4775
|
+
{
|
|
4776
|
+
cx,
|
|
4777
|
+
cy,
|
|
4778
|
+
r: radius,
|
|
4779
|
+
fill: "none",
|
|
4780
|
+
stroke: "currentColor",
|
|
4781
|
+
strokeWidth: STROKE_WIDTH,
|
|
4782
|
+
className: "text-surface-container-highest"
|
|
4783
|
+
}
|
|
4784
|
+
),
|
|
4785
|
+
/* @__PURE__ */ jsx(
|
|
4786
|
+
"circle",
|
|
4787
|
+
{
|
|
4788
|
+
cx,
|
|
4789
|
+
cy,
|
|
4790
|
+
r: radius,
|
|
4791
|
+
fill: "none",
|
|
4792
|
+
stroke: "currentColor",
|
|
4793
|
+
strokeWidth: STROKE_WIDTH,
|
|
4794
|
+
strokeLinecap: "round",
|
|
4795
|
+
className: "text-primary duration-medium4 ease-standard transition-[stroke-dashoffset]",
|
|
4796
|
+
strokeDasharray: circumference,
|
|
4797
|
+
strokeDashoffset
|
|
4798
|
+
}
|
|
4799
|
+
)
|
|
4800
|
+
] }) });
|
|
4801
|
+
}
|
|
4802
|
+
var ProgressHeadless = forwardRef(
|
|
4803
|
+
({
|
|
4804
|
+
type = "linear",
|
|
4805
|
+
indeterminate = false,
|
|
4806
|
+
size = "medium",
|
|
4807
|
+
className,
|
|
4808
|
+
children,
|
|
4809
|
+
renderProgress,
|
|
4810
|
+
label,
|
|
4811
|
+
value = 0,
|
|
4812
|
+
minValue = 0,
|
|
4813
|
+
maxValue = 100,
|
|
4814
|
+
...restProps
|
|
4815
|
+
}, forwardedRef) => {
|
|
4816
|
+
const internalRef = useRef(null);
|
|
4817
|
+
const ref = forwardedRef ?? internalRef;
|
|
4818
|
+
const { progressBarProps, labelProps } = useProgressBar({
|
|
4819
|
+
label,
|
|
4820
|
+
value,
|
|
4821
|
+
minValue,
|
|
4822
|
+
maxValue,
|
|
4823
|
+
isIndeterminate: indeterminate,
|
|
4824
|
+
...restProps
|
|
4825
|
+
});
|
|
4826
|
+
const percentage = indeterminate ? 0 : (value - minValue) / (maxValue - minValue) * 100;
|
|
4827
|
+
return /* @__PURE__ */ jsxs("div", { ...progressBarProps, ref, className, children: [
|
|
4828
|
+
label && /* @__PURE__ */ jsx("span", { ...labelProps, children: label }),
|
|
4829
|
+
renderProgress?.({
|
|
4830
|
+
percentage,
|
|
4831
|
+
isIndeterminate: indeterminate,
|
|
4832
|
+
type,
|
|
4833
|
+
size
|
|
4834
|
+
}),
|
|
4835
|
+
children
|
|
4836
|
+
] });
|
|
4837
|
+
}
|
|
4838
|
+
);
|
|
4839
|
+
ProgressHeadless.displayName = "ProgressHeadless";
|
|
4840
|
+
var MenuContext = createContext(null);
|
|
4841
|
+
function useMenuContext() {
|
|
4842
|
+
return useContext(MenuContext);
|
|
4843
|
+
}
|
|
4844
|
+
function TriggerBridge({ children }) {
|
|
4845
|
+
const ctx = useSlottedContext(ButtonContext);
|
|
4846
|
+
const localRef = useRef(null);
|
|
4847
|
+
const { ref: contextRef, ...ctxProps } = ctx ?? {};
|
|
4848
|
+
const mergedCallbackRef = useCallback(
|
|
4849
|
+
(node) => {
|
|
4850
|
+
localRef.current = node;
|
|
4851
|
+
if (!contextRef) return;
|
|
4852
|
+
if (typeof contextRef === "function") {
|
|
4853
|
+
contextRef(node);
|
|
4854
|
+
} else {
|
|
4855
|
+
contextRef.current = node;
|
|
4856
|
+
}
|
|
4857
|
+
},
|
|
4858
|
+
[contextRef]
|
|
4859
|
+
);
|
|
4860
|
+
const { buttonProps } = useButton({ ...ctxProps, elementType: "button" }, localRef);
|
|
4861
|
+
if (!isValidElement(children)) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
4862
|
+
return cloneElement(
|
|
4863
|
+
children,
|
|
4864
|
+
{ ...buttonProps, ref: mergedCallbackRef }
|
|
4865
|
+
);
|
|
4866
|
+
}
|
|
4867
|
+
function HeadlessMenuTrigger({
|
|
4868
|
+
children,
|
|
4869
|
+
placement = "bottom start",
|
|
4870
|
+
shouldFlip = true,
|
|
4871
|
+
...rest
|
|
4872
|
+
}) {
|
|
4873
|
+
const childrenArray = Array.isArray(children) ? children : [children];
|
|
4874
|
+
const [triggerChild, menuChild] = childrenArray;
|
|
4875
|
+
return /* @__PURE__ */ jsxs(MenuTrigger$1, { ...rest, children: [
|
|
4876
|
+
/* @__PURE__ */ jsx(TriggerBridge, { children: triggerChild }),
|
|
4877
|
+
/* @__PURE__ */ jsx(Popover, { placement, shouldFlip, offset: 4, children: menuChild })
|
|
4878
|
+
] });
|
|
4879
|
+
}
|
|
4880
|
+
function HeadlessMenu({
|
|
4881
|
+
className,
|
|
4882
|
+
children,
|
|
4883
|
+
"aria-label": ariaLabel,
|
|
4884
|
+
...props
|
|
4885
|
+
}) {
|
|
4886
|
+
const menuRef = useRef(null);
|
|
4887
|
+
useLayoutEffect(() => {
|
|
4888
|
+
if (ariaLabel && menuRef.current) {
|
|
4889
|
+
menuRef.current.removeAttribute("aria-labelledby");
|
|
4890
|
+
}
|
|
4891
|
+
});
|
|
4892
|
+
return /* @__PURE__ */ jsx(
|
|
4893
|
+
Menu$1,
|
|
4894
|
+
{
|
|
4895
|
+
...props,
|
|
4896
|
+
ref: menuRef,
|
|
4897
|
+
...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
|
|
4898
|
+
className: className ?? "",
|
|
4899
|
+
children
|
|
4900
|
+
}
|
|
4901
|
+
);
|
|
4902
|
+
}
|
|
4903
|
+
HeadlessMenuTrigger.Menu = HeadlessMenu;
|
|
4904
|
+
var HeadlessMenuItem = forwardRef(
|
|
4905
|
+
function HeadlessMenuItem2({ children, className, ...props }, ref) {
|
|
4906
|
+
return /* @__PURE__ */ jsx(MenuItem$1, { ...props, ref, className: className ?? "", children });
|
|
4907
|
+
}
|
|
4908
|
+
);
|
|
4909
|
+
function HeadlessMenuSection({
|
|
4910
|
+
children,
|
|
4911
|
+
"aria-label": ariaLabel,
|
|
4912
|
+
className
|
|
4913
|
+
}) {
|
|
4914
|
+
return /* @__PURE__ */ jsx(
|
|
4915
|
+
MenuSection$1,
|
|
4916
|
+
{
|
|
4917
|
+
...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
|
|
4918
|
+
className: className ?? "",
|
|
4919
|
+
children
|
|
4920
|
+
}
|
|
4921
|
+
);
|
|
4922
|
+
}
|
|
4923
|
+
function HeadlessMenuDivider({
|
|
4924
|
+
className,
|
|
4925
|
+
...props
|
|
4926
|
+
}) {
|
|
4927
|
+
return /* @__PURE__ */ jsx(Separator, { ...props, className: className ?? "" });
|
|
4928
|
+
}
|
|
4929
|
+
var menuContainerVariants = cva(
|
|
4930
|
+
[
|
|
4931
|
+
// Elevation
|
|
4932
|
+
"shadow-elevation-2",
|
|
4933
|
+
// Width constraints per MD3 spec (112dp min / 280dp max)
|
|
4934
|
+
"min-w-28 max-w-70",
|
|
4935
|
+
// Layout
|
|
4936
|
+
"py-2",
|
|
4937
|
+
// Scroll: show scrollbar when content overflows; max height avoids clipping
|
|
4938
|
+
"overflow-y-auto",
|
|
4939
|
+
"max-h-[calc(var(--visual-viewport-height,100vh)-2rem)]",
|
|
4940
|
+
// Stacking
|
|
4941
|
+
"z-50",
|
|
4942
|
+
// Focus outline handled by React Aria
|
|
4943
|
+
"outline-none",
|
|
4944
|
+
// GPU compositing — promotes menu to its own compositor layer so
|
|
4945
|
+
// scale + opacity animations run without triggering layout reflow.
|
|
4946
|
+
"will-change-[transform,opacity]",
|
|
4947
|
+
// Pointer events blocked during animation to prevent accidental clicks
|
|
4948
|
+
// on menu items while the panel is still animating in or out.
|
|
4949
|
+
"data-[entering]:pointer-events-none data-[exiting]:pointer-events-none",
|
|
4950
|
+
// ── Enter animation ────────────────────────────────────────────────────
|
|
4951
|
+
// @keyframes menu-enter (defined in styles.css): scale(0.8)+opacity:0 →
|
|
4952
|
+
// scale(1)+opacity:1 in 120ms with cubic-bezier(0,0,0.2,1) (standard
|
|
4953
|
+
// decelerate — matches Angular Material's _mat-menu-enter keyframe).
|
|
4954
|
+
"data-[entering]:animate-[menu-enter_120ms_cubic-bezier(0,0,0.2,1)_both]",
|
|
4955
|
+
// ── Exit animation ─────────────────────────────────────────────────────
|
|
4956
|
+
// @keyframes menu-exit (defined in styles.css): opacity:1 → opacity:0
|
|
4957
|
+
// in 100ms after 25ms delay, linear — matches Angular Material's
|
|
4958
|
+
// _mat-menu-exit keyframe (fade-only, no reverse scale).
|
|
4959
|
+
"data-[exiting]:animate-[menu-exit_100ms_25ms_linear_both]",
|
|
4960
|
+
// ── Transform origin (placement-aware) ────────────────────────────────
|
|
4961
|
+
// RAC sets data-placement="bottom|top|left|right" on the Popover element.
|
|
4962
|
+
// Default (bottom): origin at top edge (menu expands downward).
|
|
4963
|
+
"origin-top",
|
|
4964
|
+
// top: origin at bottom edge (menu expands upward)
|
|
4965
|
+
"data-[placement=top]:origin-bottom",
|
|
4966
|
+
// left: origin at right edge
|
|
4967
|
+
"data-[placement=left]:origin-right",
|
|
4968
|
+
// right: origin at left edge
|
|
4969
|
+
"data-[placement=right]:origin-left",
|
|
4970
|
+
// ── Reduced motion ────────────────────────────────────────────────────
|
|
4971
|
+
// Skip both animations entirely for users who prefer reduced motion.
|
|
4972
|
+
"motion-reduce:data-[entering]:animate-none motion-reduce:data-[exiting]:animate-none"
|
|
4973
|
+
],
|
|
4974
|
+
{
|
|
4975
|
+
variants: {
|
|
4976
|
+
/**
|
|
4977
|
+
* Color scheme — drives the container background.
|
|
4978
|
+
* baseline+standard uses a separate compound variant.
|
|
4979
|
+
*/
|
|
4980
|
+
colorScheme: {
|
|
4981
|
+
standard: [],
|
|
4982
|
+
vibrant: []
|
|
4983
|
+
},
|
|
4984
|
+
/**
|
|
4985
|
+
* Visual style — drives corner radius and baseline vs vertical background.
|
|
4986
|
+
*/
|
|
4987
|
+
menuStyle: {
|
|
4988
|
+
baseline: ["rounded-xs", "bg-surface-container"],
|
|
4989
|
+
vertical: ["rounded-lg", "bg-surface-container-low"]
|
|
4990
|
+
}
|
|
4991
|
+
},
|
|
4992
|
+
compoundVariants: [
|
|
4993
|
+
// Vertical + vibrant: tertiary container background
|
|
4994
|
+
{
|
|
4995
|
+
menuStyle: "vertical",
|
|
4996
|
+
colorScheme: "vibrant",
|
|
4997
|
+
class: ["bg-tertiary-container"]
|
|
4998
|
+
}
|
|
4999
|
+
],
|
|
5000
|
+
defaultVariants: {
|
|
5001
|
+
colorScheme: "standard",
|
|
5002
|
+
menuStyle: "baseline"
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
);
|
|
5006
|
+
var menuItemVariants = cva(
|
|
5007
|
+
[
|
|
5008
|
+
// Layout — height set by density context in MenuItem component
|
|
5009
|
+
"relative flex w-full items-center",
|
|
5010
|
+
"px-3 gap-3",
|
|
5011
|
+
// Typography: Body Large per MD3 baseline spec
|
|
5012
|
+
"text-body-large",
|
|
5013
|
+
// Interaction
|
|
5014
|
+
"cursor-pointer select-none outline-none",
|
|
5015
|
+
// State layer pseudo-element
|
|
5016
|
+
"before:absolute before:inset-0 before:rounded-[inherit]",
|
|
5017
|
+
"before:transition-opacity before:duration-short2 before:ease-standard",
|
|
5018
|
+
"before:opacity-0",
|
|
5019
|
+
// Hover state layer
|
|
5020
|
+
"hover:before:opacity-8",
|
|
5021
|
+
// Focus visible state layer
|
|
5022
|
+
"focus-visible:before:opacity-12",
|
|
5023
|
+
// Active pressed state layer
|
|
5024
|
+
"active:before:opacity-12",
|
|
5025
|
+
// Color transition for selection
|
|
5026
|
+
"transition-colors duration-short2 ease-standard"
|
|
5027
|
+
],
|
|
5028
|
+
{
|
|
5029
|
+
variants: {
|
|
5030
|
+
/**
|
|
5031
|
+
* Disabled state: reduces opacity and blocks interaction.
|
|
5032
|
+
*/
|
|
5033
|
+
isDisabled: {
|
|
5034
|
+
true: ["opacity-38 cursor-not-allowed pointer-events-none"],
|
|
5035
|
+
false: []
|
|
5036
|
+
},
|
|
5037
|
+
/**
|
|
5038
|
+
* Selected state: background and text color driven by compound variants.
|
|
5039
|
+
*/
|
|
5040
|
+
isSelected: {
|
|
5041
|
+
true: [],
|
|
5042
|
+
false: []
|
|
5043
|
+
},
|
|
5044
|
+
/**
|
|
5045
|
+
* Color scheme: drives default text and state layer colors.
|
|
5046
|
+
* - standard: on-surface text, on-surface state layer
|
|
5047
|
+
* - vibrant (vertical only): on-tertiary-container text + state layer
|
|
5048
|
+
*/
|
|
5049
|
+
colorScheme: {
|
|
5050
|
+
standard: ["text-on-surface", "before:bg-on-surface"],
|
|
5051
|
+
vibrant: ["text-on-tertiary-container", "before:bg-on-tertiary-container"]
|
|
5052
|
+
},
|
|
5053
|
+
/**
|
|
5054
|
+
* Visual style: drives corner radius on items (vertical uses rounded-lg
|
|
5055
|
+
* inherited from container, items stay flat inside).
|
|
5056
|
+
*/
|
|
5057
|
+
menuStyle: {
|
|
5058
|
+
baseline: [],
|
|
5059
|
+
vertical: []
|
|
5060
|
+
}
|
|
5061
|
+
},
|
|
5062
|
+
compoundVariants: [
|
|
5063
|
+
// ── Baseline selection (both colorSchemes) ──────────────────────────
|
|
5064
|
+
{
|
|
5065
|
+
isSelected: true,
|
|
5066
|
+
menuStyle: "baseline",
|
|
5067
|
+
class: [
|
|
5068
|
+
"bg-surface-container-highest"
|
|
5069
|
+
// text-on-surface already applied by standard colorScheme variant
|
|
5070
|
+
]
|
|
5071
|
+
},
|
|
5072
|
+
// ── Vertical + Standard selection ───────────────────────────────────
|
|
5073
|
+
{
|
|
5074
|
+
isSelected: true,
|
|
5075
|
+
menuStyle: "vertical",
|
|
5076
|
+
colorScheme: "standard",
|
|
5077
|
+
class: [
|
|
5078
|
+
"bg-tertiary-container",
|
|
5079
|
+
"text-on-tertiary-container",
|
|
5080
|
+
"before:bg-on-tertiary-container"
|
|
5081
|
+
]
|
|
5082
|
+
},
|
|
5083
|
+
// ── Vertical + Vibrant selection ─────────────────────────────────────
|
|
5084
|
+
{
|
|
5085
|
+
isSelected: true,
|
|
5086
|
+
menuStyle: "vertical",
|
|
5087
|
+
colorScheme: "vibrant",
|
|
5088
|
+
class: ["bg-tertiary", "text-on-tertiary", "before:bg-on-tertiary"]
|
|
5089
|
+
}
|
|
5090
|
+
],
|
|
5091
|
+
defaultVariants: {
|
|
5092
|
+
isDisabled: false,
|
|
5093
|
+
isSelected: false,
|
|
5094
|
+
colorScheme: "standard",
|
|
5095
|
+
menuStyle: "baseline"
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
);
|
|
5099
|
+
var menuSectionVariants = cva(["flex flex-col w-full"]);
|
|
5100
|
+
var menuSectionHeaderVariants = cva([
|
|
5101
|
+
"px-3 pt-2 pb-1",
|
|
5102
|
+
"text-title-small text-on-surface-variant",
|
|
5103
|
+
"select-none"
|
|
5104
|
+
]);
|
|
5105
|
+
var menuDividerVariants = cva(["border-t border-outline-variant", "my-2 mx-0"]);
|
|
5106
|
+
cva(["h-2 w-full"]);
|
|
5107
|
+
var menuItemTrailingTextVariants = cva([
|
|
5108
|
+
"ml-auto shrink-0 text-label-large text-on-surface-variant",
|
|
5109
|
+
"select-none"
|
|
5110
|
+
]);
|
|
5111
|
+
var menuItemDescriptionVariants = cva([
|
|
5112
|
+
"text-body-medium text-on-surface-variant",
|
|
5113
|
+
"select-none"
|
|
5114
|
+
]);
|
|
5115
|
+
var Menu = forwardRef(function Menu2({
|
|
5116
|
+
children,
|
|
5117
|
+
className,
|
|
5118
|
+
colorScheme = "standard",
|
|
5119
|
+
menuStyle = "baseline",
|
|
5120
|
+
density = 0,
|
|
5121
|
+
disableRipple = false,
|
|
5122
|
+
selectionMode,
|
|
5123
|
+
selectedKeys,
|
|
5124
|
+
onSelectionChange,
|
|
5125
|
+
...props
|
|
5126
|
+
}, _ref) {
|
|
5127
|
+
const close = () => {
|
|
5128
|
+
};
|
|
5129
|
+
const contextValue = {
|
|
5130
|
+
close,
|
|
5131
|
+
disableRipple,
|
|
5132
|
+
colorScheme,
|
|
5133
|
+
menuStyle,
|
|
5134
|
+
density,
|
|
5135
|
+
...selectionMode !== void 0 ? { selectionMode } : {},
|
|
5136
|
+
...selectedKeys !== void 0 ? { selectedKeys } : {}
|
|
5137
|
+
};
|
|
5138
|
+
return /* @__PURE__ */ jsx(MenuContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
5139
|
+
HeadlessMenu,
|
|
5140
|
+
{
|
|
5141
|
+
...props,
|
|
5142
|
+
...selectionMode !== void 0 ? { selectionMode } : {},
|
|
5143
|
+
...selectedKeys !== void 0 ? { selectedKeys } : {},
|
|
5144
|
+
...onSelectionChange !== void 0 ? { onSelectionChange } : {},
|
|
5145
|
+
className: cn(menuContainerVariants({ colorScheme, menuStyle }), className),
|
|
5146
|
+
children
|
|
5147
|
+
}
|
|
5148
|
+
) });
|
|
5149
|
+
});
|
|
5150
|
+
function MenuTrigger({
|
|
5151
|
+
children,
|
|
5152
|
+
placement = "bottom start",
|
|
5153
|
+
shouldFlip = true,
|
|
5154
|
+
...rest
|
|
5155
|
+
}) {
|
|
5156
|
+
return /* @__PURE__ */ jsx(HeadlessMenuTrigger, { placement, shouldFlip, ...rest, children });
|
|
5157
|
+
}
|
|
5158
|
+
MenuTrigger.Menu = Menu;
|
|
5159
|
+
function CheckIcon() {
|
|
5160
|
+
return /* @__PURE__ */ jsx(
|
|
5161
|
+
"svg",
|
|
5162
|
+
{
|
|
5163
|
+
"data-testid": "check-icon",
|
|
5164
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
5165
|
+
viewBox: "0 0 24 24",
|
|
5166
|
+
fill: "currentColor",
|
|
5167
|
+
"aria-hidden": "true",
|
|
5168
|
+
focusable: "false",
|
|
5169
|
+
className: "h-full w-full",
|
|
5170
|
+
children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" })
|
|
5171
|
+
}
|
|
5172
|
+
);
|
|
5173
|
+
}
|
|
5174
|
+
var DENSITY_HEIGHT = {
|
|
5175
|
+
0: "h-12",
|
|
5176
|
+
[-1]: "h-11",
|
|
5177
|
+
[-2]: "h-10",
|
|
5178
|
+
[-3]: "h-9"
|
|
5179
|
+
};
|
|
5180
|
+
var MenuItem = forwardRef(function MenuItem2({
|
|
5181
|
+
children,
|
|
5182
|
+
leadingIcon,
|
|
5183
|
+
trailingIcon,
|
|
5184
|
+
trailingText,
|
|
5185
|
+
description,
|
|
5186
|
+
badge,
|
|
5187
|
+
className,
|
|
5188
|
+
disableRipple: itemDisableRipple,
|
|
5189
|
+
...props
|
|
5190
|
+
}, ref) {
|
|
5191
|
+
const ctx = useMenuContext();
|
|
5192
|
+
const disableRipple = itemDisableRipple ?? ctx?.disableRipple ?? false;
|
|
5193
|
+
const colorScheme = ctx?.colorScheme ?? "standard";
|
|
5194
|
+
const menuStyle = ctx?.menuStyle ?? "baseline";
|
|
5195
|
+
const density = ctx?.density ?? 0;
|
|
5196
|
+
const selectionMode = ctx?.selectionMode;
|
|
5197
|
+
const heightClass = DENSITY_HEIGHT[density];
|
|
5198
|
+
const isSelectionMenu = selectionMode != null;
|
|
5199
|
+
const { ripples, onMouseDown } = useRipple({ disabled: disableRipple });
|
|
5200
|
+
const computeClassName = ({ isDisabled, isSelected }) => cn(
|
|
5201
|
+
menuItemVariants({
|
|
5202
|
+
isDisabled,
|
|
5203
|
+
isSelected: isSelected ?? false,
|
|
5204
|
+
colorScheme,
|
|
5205
|
+
menuStyle
|
|
5206
|
+
}),
|
|
5207
|
+
// Height: auto when description is present (multi-line), otherwise density
|
|
5208
|
+
description ? "min-h-12 py-2 h-auto items-start" : heightClass,
|
|
5209
|
+
className
|
|
5210
|
+
);
|
|
5211
|
+
return /* @__PURE__ */ jsx(
|
|
5212
|
+
HeadlessMenuItem,
|
|
5213
|
+
{
|
|
5214
|
+
...props,
|
|
5215
|
+
ref,
|
|
5216
|
+
className: computeClassName,
|
|
5217
|
+
onMouseDown,
|
|
5218
|
+
children: ({ isSelected }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5219
|
+
!disableRipple && /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute inset-0 z-0 overflow-hidden rounded-[inherit]", children: ripples }),
|
|
5220
|
+
(leadingIcon != null || isSelectionMenu) && /* @__PURE__ */ jsx(
|
|
5221
|
+
"span",
|
|
5222
|
+
{
|
|
5223
|
+
className: "text-on-surface-variant relative z-10 flex h-6 w-6 shrink-0 items-center justify-center",
|
|
5224
|
+
"aria-hidden": "true",
|
|
5225
|
+
children: isSelectionMenu && leadingIcon == null ? isSelected ? /* @__PURE__ */ jsx(CheckIcon, {}) : null : leadingIcon
|
|
5226
|
+
}
|
|
5227
|
+
),
|
|
5228
|
+
description != null ? /* @__PURE__ */ jsxs("span", { className: "relative z-10 flex min-w-0 flex-1 flex-col", children: [
|
|
5229
|
+
/* @__PURE__ */ jsx("span", { className: "text-body-large", children }),
|
|
5230
|
+
/* @__PURE__ */ jsx("span", { className: menuItemDescriptionVariants(), children: description })
|
|
5231
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "text-body-large relative z-10 min-w-0 flex-1", children }),
|
|
5232
|
+
badge != null && /* @__PURE__ */ jsx("span", { className: "relative z-10 shrink-0", children: badge }),
|
|
5233
|
+
trailingIcon != null && trailingText == null && /* @__PURE__ */ jsx(
|
|
5234
|
+
"span",
|
|
5235
|
+
{
|
|
5236
|
+
className: "text-on-surface-variant relative z-10 ml-auto flex h-6 w-6 shrink-0 items-center justify-center",
|
|
5237
|
+
"aria-hidden": "true",
|
|
5238
|
+
children: trailingIcon
|
|
5239
|
+
}
|
|
5240
|
+
),
|
|
5241
|
+
trailingText != null && trailingIcon == null && /* @__PURE__ */ jsx(
|
|
5242
|
+
"span",
|
|
5243
|
+
{
|
|
5244
|
+
className: cn(menuItemTrailingTextVariants(), "relative z-10"),
|
|
5245
|
+
"aria-keyshortcuts": trailingText,
|
|
5246
|
+
children: trailingText
|
|
5247
|
+
}
|
|
5248
|
+
)
|
|
5249
|
+
] })
|
|
5250
|
+
}
|
|
5251
|
+
);
|
|
5252
|
+
});
|
|
5253
|
+
function MenuSection({
|
|
5254
|
+
children,
|
|
5255
|
+
header,
|
|
5256
|
+
showDivider = false,
|
|
5257
|
+
className,
|
|
5258
|
+
"aria-label": ariaLabel
|
|
5259
|
+
}) {
|
|
5260
|
+
const sectionAriaLabel = ariaLabel ?? header;
|
|
5261
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5262
|
+
showDivider && /* @__PURE__ */ jsx(HeadlessMenuDivider, { className: menuDividerVariants() }),
|
|
5263
|
+
/* @__PURE__ */ jsxs(
|
|
5264
|
+
HeadlessMenuSection,
|
|
5265
|
+
{
|
|
5266
|
+
"aria-label": sectionAriaLabel,
|
|
5267
|
+
className: cn(menuSectionVariants(), className),
|
|
5268
|
+
children: [
|
|
5269
|
+
header && /* @__PURE__ */ jsx(Header, { className: menuSectionHeaderVariants(), "aria-hidden": "true", children: header }),
|
|
5270
|
+
children
|
|
5271
|
+
]
|
|
5272
|
+
}
|
|
5273
|
+
)
|
|
5274
|
+
] });
|
|
5275
|
+
}
|
|
5276
|
+
function MenuDivider({ className }) {
|
|
5277
|
+
return /* @__PURE__ */ jsx(HeadlessMenuDivider, { className: cn(menuDividerVariants(), className) });
|
|
5278
|
+
}
|
|
5279
|
+
var SnackbarHeadless = forwardRef(
|
|
5280
|
+
function SnackbarHeadless2({
|
|
5281
|
+
message,
|
|
5282
|
+
supportingText,
|
|
5283
|
+
action,
|
|
5284
|
+
showClose,
|
|
5285
|
+
duration = 4e3,
|
|
5286
|
+
severity = "default",
|
|
5287
|
+
position = "bottom-center",
|
|
5288
|
+
onClose,
|
|
5289
|
+
children,
|
|
5290
|
+
className,
|
|
5291
|
+
getAnimationClassName
|
|
5292
|
+
}, ref) {
|
|
5293
|
+
const [animationState, setAnimationState] = useState("entering");
|
|
5294
|
+
const remainingRef = useRef(duration);
|
|
5295
|
+
const startedAtRef = useRef(Date.now());
|
|
5296
|
+
const dismissTimerRef = useRef(null);
|
|
5297
|
+
const exitFallbackRef = useRef(null);
|
|
5298
|
+
const pausedRef = useRef(false);
|
|
5299
|
+
const closedRef = useRef(false);
|
|
5300
|
+
const clearDismissTimer = useCallback(() => {
|
|
5301
|
+
if (dismissTimerRef.current !== null) {
|
|
5302
|
+
clearTimeout(dismissTimerRef.current);
|
|
5303
|
+
dismissTimerRef.current = null;
|
|
5304
|
+
}
|
|
5305
|
+
}, []);
|
|
5306
|
+
const triggerExit = useCallback(() => {
|
|
5307
|
+
if (closedRef.current) return;
|
|
5308
|
+
clearDismissTimer();
|
|
5309
|
+
setAnimationState("exiting");
|
|
5310
|
+
exitFallbackRef.current = setTimeout(() => {
|
|
5311
|
+
if (!closedRef.current) {
|
|
5312
|
+
closedRef.current = true;
|
|
5313
|
+
setAnimationState("exited");
|
|
5314
|
+
onClose?.();
|
|
5315
|
+
}
|
|
5316
|
+
}, 250);
|
|
5317
|
+
}, [clearDismissTimer, onClose]);
|
|
5318
|
+
const startDismissTimer = useCallback(
|
|
5319
|
+
(ms) => {
|
|
5320
|
+
if (ms <= 0) return;
|
|
5321
|
+
clearDismissTimer();
|
|
5322
|
+
startedAtRef.current = Date.now();
|
|
5323
|
+
dismissTimerRef.current = setTimeout(triggerExit, ms);
|
|
5324
|
+
},
|
|
5325
|
+
[clearDismissTimer, triggerExit]
|
|
5326
|
+
);
|
|
5327
|
+
useEffect(() => {
|
|
5328
|
+
let frameId;
|
|
5329
|
+
frameId = requestAnimationFrame(() => {
|
|
5330
|
+
frameId = requestAnimationFrame(() => {
|
|
5331
|
+
setAnimationState("visible");
|
|
5332
|
+
});
|
|
5333
|
+
});
|
|
5334
|
+
return () => cancelAnimationFrame(frameId);
|
|
5335
|
+
}, []);
|
|
5336
|
+
useEffect(() => {
|
|
5337
|
+
if (animationState !== "visible") return;
|
|
5338
|
+
if (duration <= 0) return;
|
|
5339
|
+
remainingRef.current = duration;
|
|
5340
|
+
startDismissTimer(duration);
|
|
5341
|
+
return clearDismissTimer;
|
|
5342
|
+
}, [animationState, duration, startDismissTimer, clearDismissTimer]);
|
|
5343
|
+
useEffect(
|
|
5344
|
+
() => () => {
|
|
5345
|
+
clearDismissTimer();
|
|
5346
|
+
if (exitFallbackRef.current !== null) {
|
|
5347
|
+
clearTimeout(exitFallbackRef.current);
|
|
5348
|
+
exitFallbackRef.current = null;
|
|
5349
|
+
}
|
|
5350
|
+
},
|
|
5351
|
+
[clearDismissTimer]
|
|
5352
|
+
);
|
|
5353
|
+
const handleTransitionEnd = useCallback(() => {
|
|
5354
|
+
if (animationState === "exiting" && !closedRef.current) {
|
|
5355
|
+
if (exitFallbackRef.current !== null) {
|
|
5356
|
+
clearTimeout(exitFallbackRef.current);
|
|
5357
|
+
exitFallbackRef.current = null;
|
|
5358
|
+
}
|
|
5359
|
+
closedRef.current = true;
|
|
5360
|
+
setAnimationState("exited");
|
|
5361
|
+
onClose?.();
|
|
5362
|
+
}
|
|
5363
|
+
}, [animationState, onClose]);
|
|
5364
|
+
const handleMouseEnter = useCallback(() => {
|
|
5365
|
+
if (pausedRef.current || animationState !== "visible") return;
|
|
5366
|
+
pausedRef.current = true;
|
|
5367
|
+
const elapsed = Date.now() - startedAtRef.current;
|
|
5368
|
+
remainingRef.current = Math.max(remainingRef.current - elapsed, 0);
|
|
5369
|
+
clearDismissTimer();
|
|
5370
|
+
}, [animationState, clearDismissTimer]);
|
|
5371
|
+
const handleMouseLeave = useCallback(() => {
|
|
5372
|
+
if (!pausedRef.current || animationState !== "visible") return;
|
|
5373
|
+
pausedRef.current = false;
|
|
5374
|
+
if (duration > 0) startDismissTimer(remainingRef.current);
|
|
5375
|
+
}, [animationState, duration, startDismissTimer]);
|
|
5376
|
+
const handleFocusIn = useCallback(() => {
|
|
5377
|
+
if (pausedRef.current || animationState !== "visible") return;
|
|
5378
|
+
pausedRef.current = true;
|
|
5379
|
+
const elapsed = Date.now() - startedAtRef.current;
|
|
5380
|
+
remainingRef.current = Math.max(remainingRef.current - elapsed, 0);
|
|
5381
|
+
clearDismissTimer();
|
|
5382
|
+
}, [animationState, clearDismissTimer]);
|
|
5383
|
+
const handleFocusOut = useCallback(() => {
|
|
5384
|
+
if (!pausedRef.current || animationState !== "visible") return;
|
|
5385
|
+
pausedRef.current = false;
|
|
5386
|
+
if (duration > 0) startDismissTimer(remainingRef.current);
|
|
5387
|
+
}, [animationState, duration, startDismissTimer]);
|
|
5388
|
+
const handleClose = useCallback(() => {
|
|
5389
|
+
triggerExit();
|
|
5390
|
+
}, [triggerExit]);
|
|
5391
|
+
const ariaProps = severity === "error" ? { role: "alert", "aria-live": "assertive", "aria-atomic": "true" } : { role: "status", "aria-live": "polite", "aria-atomic": "true" };
|
|
5392
|
+
const computedClassName = cn(className, getAnimationClassName?.(animationState, position));
|
|
5393
|
+
const childContent = typeof children === "function" ? children({ animationState, onClose: handleClose }) : children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5394
|
+
/* @__PURE__ */ jsx("span", { children: message }),
|
|
5395
|
+
supportingText && /* @__PURE__ */ jsx("span", { children: supportingText }),
|
|
5396
|
+
action && /* @__PURE__ */ jsx("button", { type: "button", onClick: action.onAction, children: action.label }),
|
|
5397
|
+
showClose && /* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Close", onClick: handleClose, children: "\u2715" })
|
|
5398
|
+
] });
|
|
5399
|
+
return (
|
|
5400
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
5401
|
+
/* @__PURE__ */ jsx(
|
|
5402
|
+
"div",
|
|
5403
|
+
{
|
|
5404
|
+
ref,
|
|
5405
|
+
className: computedClassName,
|
|
5406
|
+
...ariaProps,
|
|
5407
|
+
onMouseEnter: handleMouseEnter,
|
|
5408
|
+
onMouseLeave: handleMouseLeave,
|
|
5409
|
+
onFocus: handleFocusIn,
|
|
5410
|
+
onBlur: handleFocusOut,
|
|
5411
|
+
onTransitionEnd: handleTransitionEnd,
|
|
5412
|
+
"data-animation-state": animationState,
|
|
5413
|
+
children: childContent
|
|
5414
|
+
}
|
|
5415
|
+
)
|
|
5416
|
+
);
|
|
5417
|
+
}
|
|
5418
|
+
);
|
|
5419
|
+
SnackbarHeadless.displayName = "SnackbarHeadless";
|
|
5420
|
+
var snackbarStackContainerVariants = cva(
|
|
5421
|
+
["fixed", "z-50", "flex", "gap-2", "pointer-events-none"],
|
|
5422
|
+
{
|
|
5423
|
+
variants: {
|
|
5424
|
+
position: {
|
|
5425
|
+
"bottom-center": [
|
|
5426
|
+
"bottom-4",
|
|
5427
|
+
"left-1/2",
|
|
5428
|
+
"-translate-x-1/2",
|
|
5429
|
+
"flex-col-reverse",
|
|
5430
|
+
"items-center"
|
|
5431
|
+
],
|
|
5432
|
+
"bottom-left": ["bottom-4", "left-4", "flex-col-reverse", "items-start"],
|
|
5433
|
+
"bottom-right": ["bottom-4", "right-4", "flex-col-reverse", "items-end"],
|
|
5434
|
+
"top-center": ["top-4", "left-1/2", "-translate-x-1/2", "flex-col", "items-center"],
|
|
5435
|
+
"top-left": ["top-4", "left-4", "flex-col", "items-start"],
|
|
5436
|
+
"top-right": ["top-4", "right-4", "flex-col", "items-end"]
|
|
5437
|
+
}
|
|
5438
|
+
},
|
|
5439
|
+
defaultVariants: { position: "bottom-center" }
|
|
5440
|
+
}
|
|
5441
|
+
);
|
|
5442
|
+
var snackbarBaseVariants = cva(
|
|
5443
|
+
[
|
|
5444
|
+
// Sizing (MD3 spec: 288dp min, 568dp max)
|
|
5445
|
+
"min-w-72",
|
|
5446
|
+
"max-w-snackbar-max",
|
|
5447
|
+
"w-max",
|
|
5448
|
+
"min-h-12",
|
|
5449
|
+
// Restore pointer events so hover/focus timer pause works
|
|
5450
|
+
"pointer-events-auto",
|
|
5451
|
+
// Surface
|
|
5452
|
+
"bg-inverse-surface",
|
|
5453
|
+
// Shape: MD3 extra-small corner = 4dp
|
|
5454
|
+
"rounded-xs",
|
|
5455
|
+
// Elevation level 3
|
|
5456
|
+
"shadow-elevation-3",
|
|
5457
|
+
// Layout
|
|
5458
|
+
"flex",
|
|
5459
|
+
"items-center",
|
|
5460
|
+
"gap-x-1",
|
|
5461
|
+
"pl-4 pr-2",
|
|
5462
|
+
// Typography
|
|
5463
|
+
"text-body-medium",
|
|
5464
|
+
"text-inverse-on-surface",
|
|
5465
|
+
// Transition (properties used by both entry and exit)
|
|
5466
|
+
"transition-[opacity,transform]",
|
|
5467
|
+
"will-change-[opacity,transform]"
|
|
5468
|
+
],
|
|
5469
|
+
{
|
|
5470
|
+
variants: {
|
|
5471
|
+
/**
|
|
5472
|
+
* Whether the Snackbar has supporting text (two-line layout).
|
|
5473
|
+
* Adjusts vertical padding to MD3 spec for two-line configuration.
|
|
5474
|
+
*/
|
|
5475
|
+
twoLine: {
|
|
5476
|
+
true: "py-1",
|
|
5477
|
+
false: "py-1"
|
|
5478
|
+
}
|
|
5479
|
+
},
|
|
5480
|
+
defaultVariants: {
|
|
5481
|
+
twoLine: false
|
|
5482
|
+
}
|
|
5483
|
+
}
|
|
5484
|
+
);
|
|
5485
|
+
cva("", {
|
|
5486
|
+
variants: {
|
|
5487
|
+
position: {
|
|
5488
|
+
"bottom-center": ["bottom-4", "left-1/2", "-translate-x-1/2"],
|
|
5489
|
+
"bottom-left": ["bottom-4", "left-4"],
|
|
5490
|
+
"bottom-right": ["bottom-4", "right-4"],
|
|
5491
|
+
"top-center": ["top-4", "left-1/2", "-translate-x-1/2"],
|
|
5492
|
+
"top-left": ["top-4", "left-4"],
|
|
5493
|
+
"top-right": ["top-4", "right-4"]
|
|
5494
|
+
}
|
|
5495
|
+
},
|
|
5496
|
+
defaultVariants: {
|
|
5497
|
+
position: "bottom-center"
|
|
5498
|
+
}
|
|
5499
|
+
});
|
|
5500
|
+
var snackbarAnimationVariants = cva("", {
|
|
5501
|
+
variants: {
|
|
5502
|
+
animationState: {
|
|
5503
|
+
entering: ["opacity-0", "scale-75"],
|
|
5504
|
+
visible: ["scale-100", "opacity-100", "duration-medium1", "ease-emphasized-decelerate"],
|
|
5505
|
+
exiting: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"],
|
|
5506
|
+
exited: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"]
|
|
5507
|
+
},
|
|
5508
|
+
enterDirection: {
|
|
5509
|
+
up: ["origin-bottom"],
|
|
5510
|
+
down: ["origin-top"]
|
|
5511
|
+
}
|
|
5512
|
+
},
|
|
5513
|
+
defaultVariants: {
|
|
5514
|
+
animationState: "entering",
|
|
5515
|
+
enterDirection: "up"
|
|
5516
|
+
}
|
|
5517
|
+
});
|
|
5518
|
+
cva([...snackbarBaseVariants()], {
|
|
5519
|
+
variants: {
|
|
5520
|
+
animationState: {
|
|
5521
|
+
entering: ["opacity-0", "scale-75"],
|
|
5522
|
+
visible: ["scale-100", "opacity-100", "duration-medium1", "ease-emphasized-decelerate"],
|
|
5523
|
+
exiting: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"],
|
|
5524
|
+
exited: ["scale-75", "opacity-0", "duration-short4", "ease-standard-accelerate"]
|
|
5525
|
+
},
|
|
5526
|
+
enterDirection: {
|
|
5527
|
+
up: ["origin-bottom"],
|
|
5528
|
+
down: ["origin-top"]
|
|
5529
|
+
},
|
|
5530
|
+
position: {
|
|
5531
|
+
"bottom-center": ["bottom-4", "left-1/2", "-translate-x-1/2"],
|
|
5532
|
+
"bottom-left": ["bottom-4", "left-4"],
|
|
5533
|
+
"bottom-right": ["bottom-4", "right-4"],
|
|
5534
|
+
"top-center": ["top-4", "left-1/2", "-translate-x-1/2"],
|
|
5535
|
+
"top-left": ["top-4", "left-4"],
|
|
5536
|
+
"top-right": ["top-4", "right-4"]
|
|
5537
|
+
},
|
|
5538
|
+
twoLine: {
|
|
5539
|
+
true: "py-1",
|
|
5540
|
+
false: "py-1"
|
|
5541
|
+
}
|
|
5542
|
+
},
|
|
5543
|
+
defaultVariants: {
|
|
5544
|
+
animationState: "entering",
|
|
5545
|
+
enterDirection: "up",
|
|
5546
|
+
position: "bottom-center",
|
|
5547
|
+
twoLine: false
|
|
5548
|
+
}
|
|
5549
|
+
});
|
|
5550
|
+
var snackbarMessageVariants = cva([
|
|
5551
|
+
"flex-1",
|
|
5552
|
+
"text-body-medium",
|
|
5553
|
+
"text-inverse-on-surface"
|
|
5554
|
+
]);
|
|
5555
|
+
var snackbarSupportingTextVariants = cva([
|
|
5556
|
+
"text-body-medium",
|
|
5557
|
+
"text-inverse-on-surface",
|
|
5558
|
+
"opacity-80"
|
|
5559
|
+
]);
|
|
5560
|
+
var snackbarActionVariants = cva(["shrink-0", "text-inverse-primary"]);
|
|
5561
|
+
var snackbarCloseVariants = cva(["shrink-0", "text-inverse-on-surface"]);
|
|
5562
|
+
var snackbarContentVariants = cva(["flex", "flex-col", "flex-1", "min-w-0 py-2 pr-2"]);
|
|
5563
|
+
cva(["scale-75", "opacity-0"]);
|
|
5564
|
+
function getEnterDirection(position) {
|
|
5565
|
+
return position.startsWith("top") ? "down" : "up";
|
|
5566
|
+
}
|
|
5567
|
+
function CloseIcon() {
|
|
5568
|
+
return /* @__PURE__ */ jsx(
|
|
5569
|
+
"svg",
|
|
5570
|
+
{
|
|
5571
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
5572
|
+
width: "24",
|
|
5573
|
+
height: "24",
|
|
5574
|
+
viewBox: "0 0 24 24",
|
|
5575
|
+
fill: "currentColor",
|
|
5576
|
+
"aria-hidden": "true",
|
|
5577
|
+
children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.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 12z" })
|
|
5578
|
+
}
|
|
5579
|
+
);
|
|
5580
|
+
}
|
|
5581
|
+
var Snackbar = forwardRef(function Snackbar2({
|
|
5582
|
+
message,
|
|
5583
|
+
supportingText,
|
|
5584
|
+
action,
|
|
5585
|
+
showClose = false,
|
|
5586
|
+
duration = 4e3,
|
|
5587
|
+
severity = "default",
|
|
5588
|
+
position = "bottom-center",
|
|
5589
|
+
onClose,
|
|
5590
|
+
className
|
|
5591
|
+
}, ref) {
|
|
5592
|
+
const isTwoLine = Boolean(supportingText);
|
|
5593
|
+
const baseClassName = cn(snackbarBaseVariants({ twoLine: isTwoLine }), className);
|
|
5594
|
+
return /* @__PURE__ */ jsx(
|
|
5595
|
+
SnackbarHeadless,
|
|
5596
|
+
{
|
|
5597
|
+
ref,
|
|
5598
|
+
message,
|
|
5599
|
+
...supportingText !== void 0 && { supportingText },
|
|
5600
|
+
...action !== void 0 && { action },
|
|
5601
|
+
showClose,
|
|
5602
|
+
duration,
|
|
5603
|
+
severity,
|
|
5604
|
+
position,
|
|
5605
|
+
...onClose !== void 0 && { onClose },
|
|
5606
|
+
className: baseClassName,
|
|
5607
|
+
getAnimationClassName: (state, pos) => snackbarAnimationVariants({ animationState: state, enterDirection: getEnterDirection(pos) }),
|
|
5608
|
+
children: ({ onClose: triggerClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5609
|
+
/* @__PURE__ */ jsxs("div", { className: snackbarContentVariants(), children: [
|
|
5610
|
+
/* @__PURE__ */ jsx("span", { className: snackbarMessageVariants(), children: message }),
|
|
5611
|
+
supportingText && /* @__PURE__ */ jsx("span", { className: snackbarSupportingTextVariants(), children: supportingText })
|
|
5612
|
+
] }),
|
|
5613
|
+
action && /* @__PURE__ */ jsx("span", { className: snackbarActionVariants(), children: /* @__PURE__ */ jsx(
|
|
5614
|
+
Button,
|
|
5615
|
+
{
|
|
5616
|
+
variant: "text",
|
|
5617
|
+
onPress: action.onAction,
|
|
5618
|
+
className: "text-inverse-primary hover:text-inverse-primary",
|
|
5619
|
+
children: action.label
|
|
5620
|
+
}
|
|
5621
|
+
) }),
|
|
5622
|
+
showClose && /* @__PURE__ */ jsx("span", { className: snackbarCloseVariants(), children: /* @__PURE__ */ jsx(
|
|
5623
|
+
IconButton,
|
|
5624
|
+
{
|
|
5625
|
+
variant: "standard",
|
|
5626
|
+
"aria-label": "Close",
|
|
5627
|
+
onPress: triggerClose,
|
|
5628
|
+
className: "text-inverse-on-surface hover:text-inverse-on-surface",
|
|
5629
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
5630
|
+
}
|
|
5631
|
+
) })
|
|
5632
|
+
] })
|
|
5633
|
+
}
|
|
5634
|
+
);
|
|
5635
|
+
});
|
|
5636
|
+
Snackbar.displayName = "Snackbar";
|
|
5637
|
+
var SnackbarContext = createContext(null);
|
|
5638
|
+
function useSnackbar() {
|
|
5639
|
+
const ctx = useContext(SnackbarContext);
|
|
5640
|
+
if (!ctx) {
|
|
5641
|
+
throw new Error(
|
|
5642
|
+
"[Snackbar] useSnackbar must be used inside <SnackbarProvider>. Wrap your application (or Storybook decorator) with <SnackbarProvider>."
|
|
5643
|
+
);
|
|
5644
|
+
}
|
|
5645
|
+
return ctx;
|
|
5646
|
+
}
|
|
5647
|
+
function SnackbarProvider({ children, maxVisible = 5 }) {
|
|
5648
|
+
const [queue, setQueue] = useState([]);
|
|
5649
|
+
const counterRef = useRef(0);
|
|
5650
|
+
const baseId = useId();
|
|
5651
|
+
const showSnackbar = useCallback(
|
|
5652
|
+
(options) => {
|
|
5653
|
+
const id = `${baseId}-snackbar-${++counterRef.current}`;
|
|
5654
|
+
setQueue((prev) => [...prev, { ...options, id }]);
|
|
5655
|
+
return id;
|
|
5656
|
+
},
|
|
5657
|
+
[baseId]
|
|
5658
|
+
);
|
|
5659
|
+
const closeSnackbar = useCallback(() => {
|
|
5660
|
+
setQueue((prev) => {
|
|
5661
|
+
if (prev.length === 0) return prev;
|
|
5662
|
+
return prev.slice(1);
|
|
5663
|
+
});
|
|
5664
|
+
}, []);
|
|
5665
|
+
const removeById = useCallback((id) => {
|
|
5666
|
+
setQueue((prev) => prev.filter((item) => item.id !== id));
|
|
5667
|
+
}, []);
|
|
5668
|
+
const contextValue = { showSnackbar, closeSnackbar };
|
|
5669
|
+
const positionGroups = useMemo(() => {
|
|
5670
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5671
|
+
const countByPosition = /* @__PURE__ */ new Map();
|
|
5672
|
+
for (const item of queue) {
|
|
5673
|
+
const pos = item.position ?? "bottom-center";
|
|
5674
|
+
const count = countByPosition.get(pos) ?? 0;
|
|
5675
|
+
if (count < maxVisible) {
|
|
5676
|
+
const existing = groups.get(pos) ?? [];
|
|
5677
|
+
groups.set(pos, [...existing, item]);
|
|
5678
|
+
countByPosition.set(pos, count + 1);
|
|
5679
|
+
}
|
|
5680
|
+
}
|
|
5681
|
+
return groups;
|
|
5682
|
+
}, [queue, maxVisible]);
|
|
5683
|
+
return /* @__PURE__ */ jsxs(SnackbarContext.Provider, { value: contextValue, children: [
|
|
5684
|
+
children,
|
|
5685
|
+
typeof document !== "undefined" && createPortal(
|
|
5686
|
+
/* @__PURE__ */ jsx(Fragment, { children: Array.from(positionGroups.entries()).map(([position, items]) => /* @__PURE__ */ jsx("div", { className: snackbarStackContainerVariants({ position }), children: items.map((item) => /* @__PURE__ */ jsx(
|
|
5687
|
+
Snackbar,
|
|
5688
|
+
{
|
|
5689
|
+
message: item.message,
|
|
5690
|
+
...item.supportingText !== void 0 && {
|
|
5691
|
+
supportingText: item.supportingText
|
|
5692
|
+
},
|
|
5693
|
+
...item.action !== void 0 && { action: item.action },
|
|
5694
|
+
...item.showClose !== void 0 && { showClose: item.showClose },
|
|
5695
|
+
...item.duration !== void 0 && { duration: item.duration },
|
|
5696
|
+
...item.severity !== void 0 && { severity: item.severity },
|
|
5697
|
+
...item.position !== void 0 && { position: item.position },
|
|
5698
|
+
...item.className !== void 0 && { className: item.className },
|
|
5699
|
+
onClose: () => {
|
|
5700
|
+
item.onClose?.();
|
|
5701
|
+
removeById(item.id);
|
|
5702
|
+
}
|
|
5703
|
+
},
|
|
5704
|
+
item.id
|
|
5705
|
+
)) }, position)) }),
|
|
5706
|
+
document.body
|
|
5707
|
+
)
|
|
5708
|
+
] });
|
|
5709
|
+
}
|
|
5710
|
+
var DialogContext = createContext(null);
|
|
5711
|
+
function useDialogContext() {
|
|
5712
|
+
const ctx = useContext(DialogContext);
|
|
5713
|
+
if (ctx === null) {
|
|
5714
|
+
throw new Error(
|
|
5715
|
+
"[Dialog] DialogHeadline, DialogContent, and DialogActions must be rendered inside a <Dialog> or <DialogHeadless> component."
|
|
5716
|
+
);
|
|
5717
|
+
}
|
|
5718
|
+
return ctx;
|
|
5719
|
+
}
|
|
5720
|
+
var DialogPanel = ({
|
|
5721
|
+
ariaLabel,
|
|
5722
|
+
headlineId,
|
|
5723
|
+
contentId,
|
|
5724
|
+
onClose,
|
|
5725
|
+
onTransitionEnd,
|
|
5726
|
+
variant,
|
|
5727
|
+
isDismissable,
|
|
5728
|
+
wrapperClassName,
|
|
5729
|
+
className,
|
|
5730
|
+
animationState,
|
|
5731
|
+
getAnimationClassName,
|
|
5732
|
+
children
|
|
5733
|
+
}) => {
|
|
5734
|
+
const panelRef = useRef(null);
|
|
5735
|
+
usePreventScroll();
|
|
5736
|
+
const { dialogProps } = useDialog(
|
|
5737
|
+
{
|
|
5738
|
+
...ariaLabel ? { "aria-label": ariaLabel } : {},
|
|
5739
|
+
"aria-labelledby": headlineId,
|
|
5740
|
+
"aria-describedby": contentId
|
|
5741
|
+
},
|
|
5742
|
+
panelRef
|
|
5743
|
+
);
|
|
5744
|
+
const { overlayProps } = useOverlay(
|
|
5745
|
+
{
|
|
5746
|
+
isOpen: true,
|
|
5747
|
+
onClose,
|
|
5748
|
+
isDismissable,
|
|
5749
|
+
shouldCloseOnBlur: false
|
|
5750
|
+
},
|
|
5751
|
+
panelRef
|
|
5752
|
+
);
|
|
5753
|
+
const panelClassName = cn(className, getAnimationClassName?.(animationState));
|
|
5754
|
+
return (
|
|
5755
|
+
// Centering/positioning wrapper — structural only, no ARIA role
|
|
5756
|
+
/* @__PURE__ */ jsx("div", { className: wrapperClassName, children: /* @__PURE__ */ jsx(
|
|
5757
|
+
"div",
|
|
5758
|
+
{
|
|
5759
|
+
...mergeProps(overlayProps, dialogProps),
|
|
5760
|
+
ref: panelRef,
|
|
5761
|
+
"aria-modal": "true",
|
|
5762
|
+
className: panelClassName,
|
|
5763
|
+
"data-animation-state": animationState,
|
|
5764
|
+
"data-variant": variant,
|
|
5765
|
+
onTransitionEnd,
|
|
5766
|
+
children
|
|
5767
|
+
}
|
|
5768
|
+
) })
|
|
5769
|
+
);
|
|
5770
|
+
};
|
|
5771
|
+
DialogPanel.displayName = "DialogPanel";
|
|
5772
|
+
var DialogHeadless = forwardRef(
|
|
5773
|
+
function DialogHeadless2({
|
|
5774
|
+
variant = "basic",
|
|
5775
|
+
open,
|
|
5776
|
+
defaultOpen = false,
|
|
5777
|
+
onOpenChange,
|
|
5778
|
+
"aria-label": ariaLabel,
|
|
5779
|
+
children,
|
|
5780
|
+
className,
|
|
5781
|
+
scrimClassName,
|
|
5782
|
+
getAnimationClassName
|
|
5783
|
+
}, _ref) {
|
|
5784
|
+
const state = useOverlayTriggerState({
|
|
5785
|
+
...open !== void 0 ? { isOpen: open } : {},
|
|
5786
|
+
...defaultOpen !== void 0 ? { defaultOpen } : {},
|
|
5787
|
+
...onOpenChange !== void 0 ? { onOpenChange } : {}
|
|
5788
|
+
});
|
|
5789
|
+
const isOpen = state.isOpen;
|
|
5790
|
+
const close = useCallback(() => {
|
|
5791
|
+
state.close();
|
|
5792
|
+
}, [state]);
|
|
5793
|
+
const [animationState, setAnimationState] = useState("exited");
|
|
5794
|
+
const closedRef = useRef(false);
|
|
5795
|
+
const exitFallbackRef = useRef(null);
|
|
5796
|
+
useEffect(() => {
|
|
5797
|
+
if (!isOpen) return;
|
|
5798
|
+
closedRef.current = false;
|
|
5799
|
+
setAnimationState("entering");
|
|
5800
|
+
const id = setTimeout(() => {
|
|
5801
|
+
setAnimationState("visible");
|
|
5802
|
+
}, 0);
|
|
5803
|
+
return () => clearTimeout(id);
|
|
5804
|
+
}, [isOpen]);
|
|
5805
|
+
useEffect(() => {
|
|
5806
|
+
if (isOpen) return;
|
|
5807
|
+
if (animationState === "exited" || animationState === "entering") return;
|
|
5808
|
+
if (animationState === "visible") {
|
|
5809
|
+
setAnimationState("exiting");
|
|
5810
|
+
exitFallbackRef.current = setTimeout(() => {
|
|
5811
|
+
if (!closedRef.current) {
|
|
5812
|
+
closedRef.current = true;
|
|
5813
|
+
setAnimationState("exited");
|
|
5814
|
+
}
|
|
5815
|
+
}, 150);
|
|
5816
|
+
}
|
|
5817
|
+
}, [isOpen, animationState]);
|
|
5818
|
+
useEffect(
|
|
5819
|
+
() => () => {
|
|
5820
|
+
if (exitFallbackRef.current !== null) {
|
|
5821
|
+
clearTimeout(exitFallbackRef.current);
|
|
5822
|
+
}
|
|
5823
|
+
},
|
|
5824
|
+
[]
|
|
5825
|
+
);
|
|
5826
|
+
const handleTransitionEnd = useCallback(() => {
|
|
5827
|
+
if (animationState === "exiting" && !closedRef.current) {
|
|
5828
|
+
if (exitFallbackRef.current !== null) {
|
|
5829
|
+
clearTimeout(exitFallbackRef.current);
|
|
5830
|
+
exitFallbackRef.current = null;
|
|
5831
|
+
}
|
|
5832
|
+
closedRef.current = true;
|
|
5833
|
+
setAnimationState("exited");
|
|
5834
|
+
}
|
|
5835
|
+
}, [animationState]);
|
|
5836
|
+
const baseId = useId();
|
|
5837
|
+
const headlineId = `${baseId}-dialog-headline`;
|
|
5838
|
+
const contentId = `${baseId}-dialog-content`;
|
|
5839
|
+
const contextValue = {
|
|
5840
|
+
headlineId,
|
|
5841
|
+
contentId,
|
|
5842
|
+
close,
|
|
5843
|
+
variant
|
|
5844
|
+
};
|
|
5845
|
+
const handleScrimClick = useCallback(() => {
|
|
5846
|
+
if (variant === "basic") {
|
|
5847
|
+
close();
|
|
5848
|
+
}
|
|
5849
|
+
}, [variant, close]);
|
|
5850
|
+
if (!isOpen && animationState === "exited") {
|
|
5851
|
+
return null;
|
|
5852
|
+
}
|
|
5853
|
+
const content = /* @__PURE__ */ jsxs(DialogContext.Provider, { value: contextValue, children: [
|
|
5854
|
+
/* @__PURE__ */ jsx(
|
|
5855
|
+
"div",
|
|
5856
|
+
{
|
|
5857
|
+
"data-testid": "dialog-scrim",
|
|
5858
|
+
className: scrimClassName,
|
|
5859
|
+
onClick: handleScrimClick,
|
|
5860
|
+
"aria-hidden": "true"
|
|
5861
|
+
}
|
|
5862
|
+
),
|
|
5863
|
+
/* @__PURE__ */ jsx(FocusScope, { contain: true, restoreFocus: true, autoFocus: true, children: /* @__PURE__ */ jsx(
|
|
5864
|
+
DialogPanel,
|
|
5865
|
+
{
|
|
5866
|
+
ariaLabel,
|
|
5867
|
+
headlineId,
|
|
5868
|
+
contentId,
|
|
5869
|
+
onClose: close,
|
|
5870
|
+
onTransitionEnd: handleTransitionEnd,
|
|
5871
|
+
variant,
|
|
5872
|
+
isDismissable: variant === "basic",
|
|
5873
|
+
wrapperClassName: variant === "basic" ? "fixed inset-0 z-50 flex items-center justify-center px-4" : "fixed inset-0 z-50",
|
|
5874
|
+
className,
|
|
5875
|
+
animationState,
|
|
5876
|
+
getAnimationClassName,
|
|
5877
|
+
children
|
|
5878
|
+
}
|
|
5879
|
+
) })
|
|
5880
|
+
] });
|
|
5881
|
+
if (typeof document === "undefined") return null;
|
|
5882
|
+
return createPortal(content, document.body);
|
|
5883
|
+
}
|
|
5884
|
+
);
|
|
5885
|
+
DialogHeadless.displayName = "DialogHeadless";
|
|
5886
|
+
var dialogScrimVariants = cva([
|
|
5887
|
+
"fixed",
|
|
5888
|
+
"inset-0",
|
|
5889
|
+
"z-40",
|
|
5890
|
+
"bg-scrim",
|
|
5891
|
+
"opacity-32",
|
|
5892
|
+
"transition-opacity",
|
|
5893
|
+
"duration-medium2",
|
|
5894
|
+
"ease-standard"
|
|
5895
|
+
]);
|
|
5896
|
+
var dialogPanelVariants = cva(
|
|
5897
|
+
[
|
|
5898
|
+
// Stacking above scrim
|
|
5899
|
+
"z-50",
|
|
5900
|
+
// Surface
|
|
5901
|
+
"bg-surface-container-high",
|
|
5902
|
+
// Flex column layout for slots
|
|
5903
|
+
"flex",
|
|
5904
|
+
"flex-col",
|
|
5905
|
+
// Transition for animation state changes
|
|
5906
|
+
"transition-[opacity,transform]",
|
|
5907
|
+
"will-change-[opacity,transform]"
|
|
5908
|
+
],
|
|
5909
|
+
{
|
|
5910
|
+
variants: {
|
|
5911
|
+
variant: {
|
|
5912
|
+
basic: [
|
|
5913
|
+
// Shape: MD3 extra-large = 28dp
|
|
5914
|
+
"rounded-xl",
|
|
5915
|
+
// Elevation level 3
|
|
5916
|
+
"shadow-elevation-3",
|
|
5917
|
+
// Width constraints per MD3 spec (280dp min, 560dp max)
|
|
5918
|
+
"min-w-70",
|
|
5919
|
+
"max-w-dialog-max",
|
|
5920
|
+
"w-full",
|
|
5921
|
+
// Internal spacing
|
|
5922
|
+
"pt-6",
|
|
5923
|
+
"pb-3",
|
|
5924
|
+
"px-6",
|
|
5925
|
+
// Positioned in viewport center
|
|
5926
|
+
"relative"
|
|
5927
|
+
],
|
|
5928
|
+
fullscreen: [
|
|
5929
|
+
// Full viewport
|
|
5930
|
+
"w-full",
|
|
5931
|
+
"h-full",
|
|
5932
|
+
// No rounded corners on fullscreen
|
|
5933
|
+
"rounded-none",
|
|
5934
|
+
// No elevation shadow on fullscreen
|
|
5935
|
+
"shadow-none",
|
|
5936
|
+
// Positioned to fill portal
|
|
5937
|
+
"relative"
|
|
5938
|
+
]
|
|
5939
|
+
}
|
|
5940
|
+
},
|
|
5941
|
+
defaultVariants: {
|
|
5942
|
+
variant: "basic"
|
|
5943
|
+
}
|
|
5944
|
+
}
|
|
5945
|
+
);
|
|
5946
|
+
cva([], {
|
|
5947
|
+
variants: {
|
|
5948
|
+
variant: {
|
|
5949
|
+
basic: ["fixed", "inset-0", "z-50", "flex", "items-center", "justify-center", "px-4"],
|
|
5950
|
+
fullscreen: ["fixed", "inset-0", "z-50"]
|
|
5951
|
+
}
|
|
5952
|
+
},
|
|
5953
|
+
defaultVariants: {
|
|
5954
|
+
variant: "basic"
|
|
5955
|
+
}
|
|
5956
|
+
});
|
|
5957
|
+
var dialogAnimationVariants = cva("", {
|
|
5958
|
+
variants: {
|
|
5959
|
+
animationState: {
|
|
5960
|
+
entering: [],
|
|
5961
|
+
visible: [],
|
|
5962
|
+
exiting: [],
|
|
5963
|
+
exited: []
|
|
5964
|
+
},
|
|
5965
|
+
variant: {
|
|
5966
|
+
basic: [],
|
|
5967
|
+
fullscreen: []
|
|
5968
|
+
}
|
|
5969
|
+
},
|
|
5970
|
+
compoundVariants: [
|
|
5971
|
+
// Basic: entering — start scaled down + transparent
|
|
5972
|
+
{
|
|
5973
|
+
animationState: "entering",
|
|
5974
|
+
variant: "basic",
|
|
5975
|
+
className: ["scale-90", "opacity-0"]
|
|
5976
|
+
},
|
|
5977
|
+
// Basic: visible — scale to full + fade in
|
|
5978
|
+
{
|
|
5979
|
+
animationState: "visible",
|
|
5980
|
+
variant: "basic",
|
|
5981
|
+
className: ["scale-100", "opacity-100", "duration-medium4", "ease-emphasized-decelerate"]
|
|
5982
|
+
},
|
|
5983
|
+
// Basic: exiting — fade out (scale stays at 1)
|
|
5984
|
+
{
|
|
5985
|
+
animationState: "exiting",
|
|
5986
|
+
variant: "basic",
|
|
5987
|
+
className: ["scale-100", "opacity-0", "duration-short2", "ease-emphasized-accelerate"]
|
|
5988
|
+
},
|
|
5989
|
+
// Basic: exited — fully transparent
|
|
5990
|
+
{
|
|
5991
|
+
animationState: "exited",
|
|
5992
|
+
variant: "basic",
|
|
5993
|
+
className: ["scale-100", "opacity-0"]
|
|
5994
|
+
},
|
|
5995
|
+
// Fullscreen: entering — start below viewport + transparent
|
|
5996
|
+
{
|
|
5997
|
+
animationState: "entering",
|
|
5998
|
+
variant: "fullscreen",
|
|
5999
|
+
className: ["translate-y-full", "opacity-0"]
|
|
6000
|
+
},
|
|
6001
|
+
// Fullscreen: visible — slide up + fade in
|
|
6002
|
+
{
|
|
6003
|
+
animationState: "visible",
|
|
6004
|
+
variant: "fullscreen",
|
|
6005
|
+
className: ["translate-y-0", "opacity-100", "duration-medium4", "ease-emphasized-decelerate"]
|
|
6006
|
+
},
|
|
6007
|
+
// Fullscreen: exiting — slide down + fade out
|
|
6008
|
+
{
|
|
6009
|
+
animationState: "exiting",
|
|
6010
|
+
variant: "fullscreen",
|
|
6011
|
+
className: ["translate-y-full", "opacity-0", "duration-short2", "ease-emphasized-accelerate"]
|
|
6012
|
+
},
|
|
6013
|
+
// Fullscreen: exited — fully off-screen
|
|
6014
|
+
{
|
|
6015
|
+
animationState: "exited",
|
|
6016
|
+
variant: "fullscreen",
|
|
6017
|
+
className: ["translate-y-full", "opacity-0"]
|
|
6018
|
+
}
|
|
6019
|
+
],
|
|
6020
|
+
defaultVariants: {
|
|
6021
|
+
animationState: "entering",
|
|
6022
|
+
variant: "basic"
|
|
6023
|
+
}
|
|
6024
|
+
});
|
|
6025
|
+
var dialogHeadlineVariants = cva(["text-headline-small", "text-on-surface"], {
|
|
6026
|
+
variants: {
|
|
6027
|
+
variant: {
|
|
6028
|
+
basic: ["mb-4"],
|
|
6029
|
+
fullscreen: [
|
|
6030
|
+
// Top app bar row in fullscreen: flex, items-center, gap
|
|
6031
|
+
"flex",
|
|
6032
|
+
"items-center",
|
|
6033
|
+
"gap-4",
|
|
6034
|
+
"px-4",
|
|
6035
|
+
"h-14",
|
|
6036
|
+
"shrink-0",
|
|
6037
|
+
"border-b",
|
|
6038
|
+
"border-outline-variant"
|
|
6039
|
+
]
|
|
6040
|
+
}
|
|
6041
|
+
},
|
|
6042
|
+
defaultVariants: {
|
|
6043
|
+
variant: "basic"
|
|
6044
|
+
}
|
|
6045
|
+
});
|
|
6046
|
+
var dialogHeadlineTitleVariants = cva([
|
|
6047
|
+
"flex-1",
|
|
6048
|
+
"text-headline-small",
|
|
6049
|
+
"text-on-surface",
|
|
6050
|
+
"truncate"
|
|
6051
|
+
]);
|
|
6052
|
+
var dialogContentVariants = cva(
|
|
6053
|
+
["text-body-medium", "text-on-surface-variant", "overflow-y-auto", "flex-1"],
|
|
6054
|
+
{
|
|
6055
|
+
variants: {
|
|
6056
|
+
variant: {
|
|
6057
|
+
basic: ["mb-6"],
|
|
6058
|
+
fullscreen: ["px-6", "py-4"]
|
|
6059
|
+
}
|
|
6060
|
+
},
|
|
6061
|
+
defaultVariants: {
|
|
6062
|
+
variant: "basic"
|
|
6063
|
+
}
|
|
6064
|
+
}
|
|
6065
|
+
);
|
|
6066
|
+
var dialogActionsVariants = cva([
|
|
6067
|
+
"flex",
|
|
6068
|
+
"items-center",
|
|
6069
|
+
"justify-end",
|
|
6070
|
+
"gap-2",
|
|
6071
|
+
"pt-3",
|
|
6072
|
+
"shrink-0"
|
|
6073
|
+
]);
|
|
6074
|
+
var Dialog = forwardRef(function Dialog2({
|
|
6075
|
+
variant = "basic",
|
|
6076
|
+
open,
|
|
6077
|
+
defaultOpen = false,
|
|
6078
|
+
onOpenChange,
|
|
6079
|
+
"aria-label": ariaLabel,
|
|
6080
|
+
children,
|
|
6081
|
+
className
|
|
6082
|
+
}, _ref) {
|
|
6083
|
+
const panelClassName = cn(dialogPanelVariants({ variant }), className);
|
|
6084
|
+
const scrimClass = dialogScrimVariants();
|
|
6085
|
+
return /* @__PURE__ */ jsx(
|
|
6086
|
+
DialogHeadless,
|
|
6087
|
+
{
|
|
6088
|
+
variant,
|
|
6089
|
+
...open !== void 0 ? { open } : {},
|
|
6090
|
+
...defaultOpen !== void 0 ? { defaultOpen } : {},
|
|
6091
|
+
...onOpenChange !== void 0 ? { onOpenChange } : {},
|
|
6092
|
+
...ariaLabel ? { "aria-label": ariaLabel } : {},
|
|
6093
|
+
className: panelClassName,
|
|
6094
|
+
scrimClassName: scrimClass,
|
|
6095
|
+
getAnimationClassName: (state) => dialogAnimationVariants({ animationState: state, variant }),
|
|
6096
|
+
children
|
|
6097
|
+
}
|
|
6098
|
+
);
|
|
6099
|
+
});
|
|
6100
|
+
Dialog.displayName = "Dialog";
|
|
6101
|
+
var DialogHeadline = forwardRef(
|
|
6102
|
+
function DialogHeadline2({ children, className, closeButton, confirmButton }, ref) {
|
|
6103
|
+
const { headlineId, variant } = useDialogContext();
|
|
6104
|
+
if (variant === "fullscreen") {
|
|
6105
|
+
return (
|
|
6106
|
+
// Top app bar row for fullscreen variant
|
|
6107
|
+
/* @__PURE__ */ jsxs("div", { className: cn(dialogHeadlineVariants({ variant: "fullscreen" }), className), children: [
|
|
6108
|
+
closeButton,
|
|
6109
|
+
/* @__PURE__ */ jsx("h2", { id: headlineId, className: dialogHeadlineTitleVariants(), children }),
|
|
6110
|
+
confirmButton
|
|
6111
|
+
] })
|
|
6112
|
+
);
|
|
6113
|
+
}
|
|
6114
|
+
return /* @__PURE__ */ jsx(
|
|
6115
|
+
"h2",
|
|
6116
|
+
{
|
|
6117
|
+
ref,
|
|
6118
|
+
id: headlineId,
|
|
6119
|
+
className: cn(dialogHeadlineVariants({ variant: "basic" }), className),
|
|
6120
|
+
children
|
|
6121
|
+
}
|
|
6122
|
+
);
|
|
6123
|
+
}
|
|
6124
|
+
);
|
|
6125
|
+
DialogHeadline.displayName = "DialogHeadline";
|
|
6126
|
+
var DialogContent = forwardRef(function DialogContent2({ children, className }, ref) {
|
|
6127
|
+
const { contentId, variant } = useDialogContext();
|
|
6128
|
+
return /* @__PURE__ */ jsx("div", { ref, id: contentId, className: cn(dialogContentVariants({ variant }), className), children });
|
|
6129
|
+
});
|
|
6130
|
+
DialogContent.displayName = "DialogContent";
|
|
6131
|
+
var DialogActions = forwardRef(function DialogActions2({ children, className }, ref) {
|
|
6132
|
+
useDialogContext();
|
|
6133
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn(dialogActionsVariants(), className), children });
|
|
6134
|
+
});
|
|
6135
|
+
DialogActions.displayName = "DialogActions";
|
|
4501
6136
|
|
|
4502
|
-
export { AppBar, AppBarHeadless, Button, Checkbox, Drawer, DrawerItem, DrawerSection, FAB, FABHeadless, HeadlessDrawer, HeadlessDrawerItem, HeadlessNavigationBar, HeadlessNavigationBarItem, HeadlessTab, HeadlessTabList, HeadlessTabPanel, IconButton, IconButtonHeadless, NavigationBar, NavigationBarItem, Radio, RadioGroup, RadioGroupHeadless, RadioHeadless, STATE_LAYER_OPACITY, Switch, TYPOGRAPHY_ELEMENT_MAP, TYPOGRAPHY_USAGE, Tab, TabList, TabPanel, Tabs, TextField, applyStateLayer, cn, generateMD3Theme, getColorValue, getFontFamily, getMD3Color, getResponsiveTypography, getTypographyClassName, getTypographyForElement, getTypographyStyle, getTypographyToken, hexToRgb, pxToRem, remToPx, rgbToHex, truncateText, withOpacity };
|
|
6137
|
+
export { AppBar, AppBarHeadless, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogContext, DialogHeadless, DialogHeadline, Drawer, DrawerItem, DrawerSection, FAB, FABHeadless, HeadlessDrawer, HeadlessDrawerItem, HeadlessMenu, HeadlessMenuDivider, HeadlessMenuItem, HeadlessMenuSection, HeadlessMenuTrigger, HeadlessNavigationBar, HeadlessNavigationBarItem, HeadlessTab, HeadlessTabList, HeadlessTabPanel, IconButton, IconButtonHeadless, Menu, MenuContext, MenuDivider, MenuItem, MenuSection, MenuTrigger, NavigationBar, NavigationBarItem, Progress, ProgressHeadless, Radio, RadioGroup, RadioGroupHeadless, RadioHeadless, STATE_LAYER_OPACITY, Snackbar, SnackbarContext, SnackbarHeadless, SnackbarProvider, Switch, TYPOGRAPHY_ELEMENT_MAP, TYPOGRAPHY_USAGE, Tab, TabList, TabPanel, Tabs, TextField, applyStateLayer, cn, generateMD3Theme, getColorValue, getFontFamily, getMD3Color, getResponsiveTypography, getTypographyClassName, getTypographyForElement, getTypographyStyle, getTypographyToken, hexToRgb, pxToRem, remToPx, rgbToHex, truncateText, useDialogContext, useMenuContext, useSnackbar, withOpacity };
|
|
4503
6138
|
//# sourceMappingURL=index.js.map
|
|
4504
6139
|
//# sourceMappingURL=index.js.map
|