@tinybigui/react 0.23.0 → 0.24.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 CHANGED
@@ -9,8 +9,8 @@ var classVarianceAuthority = require('class-variance-authority');
9
9
  var reactAria = require('react-aria');
10
10
  var utils = require('@react-aria/utils');
11
11
  var reactStately = require('react-stately');
12
- var reactAriaComponents = require('react-aria-components');
13
12
  var reactDom = require('react-dom');
13
+ var reactAriaComponents = require('react-aria-components');
14
14
  var date = require('@internationalized/date');
15
15
 
16
16
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -4419,7 +4419,51 @@ var NavigationBarItem = React.forwardRef(
4419
4419
  );
4420
4420
  NavigationBarItem.displayName = "NavigationBarItem";
4421
4421
  var DrawerContext = React.createContext(null);
4422
- var DrawerIconOnlyContext = React.createContext(false);
4422
+ var ModalDrawerPanel = ({
4423
+ ariaLabel,
4424
+ onClose,
4425
+ className,
4426
+ animationState,
4427
+ getAnimationClassName,
4428
+ onTransitionEnd,
4429
+ forwardedRef,
4430
+ children
4431
+ }) => {
4432
+ const panelRef = React.useRef(null);
4433
+ reactAria.usePreventScroll();
4434
+ const { dialogProps } = reactAria.useDialog(
4435
+ { "aria-label": ariaLabel },
4436
+ panelRef
4437
+ );
4438
+ const { overlayProps } = reactAria.useOverlay(
4439
+ { isOpen: true, onClose, isDismissable: true, shouldCloseOnBlur: false },
4440
+ panelRef
4441
+ );
4442
+ const setRef = React.useCallback(
4443
+ (node) => {
4444
+ panelRef.current = node;
4445
+ if (typeof forwardedRef === "function") {
4446
+ forwardedRef(node);
4447
+ } else if (forwardedRef !== null && forwardedRef !== void 0) {
4448
+ forwardedRef.current = node;
4449
+ }
4450
+ },
4451
+ [forwardedRef]
4452
+ );
4453
+ return /* @__PURE__ */ jsxRuntime.jsx(
4454
+ "div",
4455
+ {
4456
+ ...utils.mergeProps(overlayProps, dialogProps),
4457
+ ref: setRef,
4458
+ "aria-modal": "true",
4459
+ className: cn(className, getAnimationClassName?.(animationState)),
4460
+ "data-animation-state": animationState,
4461
+ onTransitionEnd,
4462
+ children
4463
+ }
4464
+ );
4465
+ };
4466
+ ModalDrawerPanel.displayName = "ModalDrawerPanel";
4423
4467
  var HeadlessDrawer = React.forwardRef(
4424
4468
  ({
4425
4469
  variant = "standard",
@@ -4430,8 +4474,9 @@ var HeadlessDrawer = React.forwardRef(
4430
4474
  children,
4431
4475
  className,
4432
4476
  scrimClassName,
4433
- disableRipple = false,
4434
- iconOnly = false
4477
+ getAnimationClassName,
4478
+ getScrimAnimationClassName,
4479
+ disableRipple = false
4435
4480
  }, ref) => {
4436
4481
  const state = reactStately.useOverlayTriggerState({
4437
4482
  ...open !== void 0 ? { isOpen: open } : {},
@@ -4442,77 +4487,99 @@ var HeadlessDrawer = React.forwardRef(
4442
4487
  const close = React.useCallback(() => {
4443
4488
  state.close();
4444
4489
  }, [state]);
4490
+ const [animationState, setAnimationState] = React.useState("exited");
4491
+ const closedRef = React.useRef(false);
4492
+ const exitFallbackRef = React.useRef(null);
4493
+ React.useEffect(() => {
4494
+ if (!isOpen) return;
4495
+ closedRef.current = false;
4496
+ setAnimationState("entering");
4497
+ const id = setTimeout(() => {
4498
+ setAnimationState("visible");
4499
+ }, 0);
4500
+ return () => clearTimeout(id);
4501
+ }, [isOpen]);
4502
+ React.useEffect(() => {
4503
+ if (isOpen) return;
4504
+ if (animationState === "exited" || animationState === "entering") return;
4505
+ if (animationState === "visible") {
4506
+ setAnimationState("exiting");
4507
+ exitFallbackRef.current = setTimeout(() => {
4508
+ if (!closedRef.current) {
4509
+ closedRef.current = true;
4510
+ setAnimationState("exited");
4511
+ }
4512
+ }, 500);
4513
+ }
4514
+ }, [isOpen, animationState]);
4515
+ React.useEffect(
4516
+ () => () => {
4517
+ if (exitFallbackRef.current !== null) {
4518
+ clearTimeout(exitFallbackRef.current);
4519
+ }
4520
+ },
4521
+ []
4522
+ );
4523
+ const handleTransitionEnd = React.useCallback(() => {
4524
+ if (animationState === "exiting" && !closedRef.current) {
4525
+ if (exitFallbackRef.current !== null) {
4526
+ clearTimeout(exitFallbackRef.current);
4527
+ exitFallbackRef.current = null;
4528
+ }
4529
+ closedRef.current = true;
4530
+ setAnimationState("exited");
4531
+ }
4532
+ }, [animationState]);
4445
4533
  const contextValue = {
4446
4534
  isOpen,
4447
4535
  close,
4448
- disableRipple,
4449
- iconOnly
4536
+ disableRipple
4450
4537
  };
4451
- if (variant === "modal") {
4452
- return /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx("nav", { ref, role: "navigation", "aria-label": ariaLabel, children: isOpen && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4453
- /* @__PURE__ */ jsxRuntime.jsx(
4454
- "div",
4455
- {
4456
- "data-testid": "drawer-scrim",
4457
- className: scrimClassName,
4458
- onClick: () => state.close(),
4459
- "aria-hidden": "true"
4460
- }
4461
- ),
4462
- /* @__PURE__ */ jsxRuntime.jsx(reactAria.FocusScope, { contain: true, restoreFocus: true, autoFocus: true, children: /* @__PURE__ */ jsxRuntime.jsx(
4463
- ModalDrawerPanel,
4464
- {
4465
- ariaLabel,
4466
- onClose: () => state.close(),
4467
- className,
4468
- children
4469
- }
4470
- ) })
4471
- ] }) }) });
4538
+ if (variant === "standard") {
4539
+ return /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
4540
+ "nav",
4541
+ {
4542
+ ref,
4543
+ role: "navigation",
4544
+ "aria-label": ariaLabel,
4545
+ className,
4546
+ children
4547
+ }
4548
+ ) });
4472
4549
  }
4473
- return /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
4474
- "nav",
4475
- {
4476
- ref,
4477
- role: "navigation",
4478
- "aria-label": ariaLabel,
4479
- className,
4480
- children
4481
- }
4482
- ) });
4550
+ if (!isOpen && animationState === "exited") {
4551
+ return null;
4552
+ }
4553
+ if (typeof document === "undefined") return null;
4554
+ const content = /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(reactAria.FocusScope, { contain: true, restoreFocus: true, autoFocus: true, children: [
4555
+ /* @__PURE__ */ jsxRuntime.jsx(
4556
+ "div",
4557
+ {
4558
+ "data-testid": "drawer-scrim",
4559
+ className: cn(scrimClassName, getScrimAnimationClassName?.(animationState)),
4560
+ "data-animation-state": animationState,
4561
+ onClick: close,
4562
+ "aria-hidden": "true"
4563
+ }
4564
+ ),
4565
+ /* @__PURE__ */ jsxRuntime.jsx(
4566
+ ModalDrawerPanel,
4567
+ {
4568
+ ariaLabel,
4569
+ onClose: close,
4570
+ className,
4571
+ animationState,
4572
+ getAnimationClassName,
4573
+ onTransitionEnd: handleTransitionEnd,
4574
+ forwardedRef: ref,
4575
+ children
4576
+ }
4577
+ )
4578
+ ] }) });
4579
+ return reactDom.createPortal(content, document.body);
4483
4580
  }
4484
4581
  );
4485
4582
  HeadlessDrawer.displayName = "HeadlessDrawer";
4486
- var ModalDrawerPanel = ({
4487
- ariaLabel,
4488
- onClose,
4489
- className,
4490
- children
4491
- }) => {
4492
- const panelRef = React.useRef(null);
4493
- reactAria.usePreventScroll();
4494
- const { dialogProps } = reactAria.useDialog({ "aria-label": ariaLabel }, panelRef);
4495
- const { overlayProps } = reactAria.useOverlay(
4496
- {
4497
- isOpen: true,
4498
- onClose,
4499
- isDismissable: true,
4500
- shouldCloseOnBlur: false
4501
- },
4502
- panelRef
4503
- );
4504
- return /* @__PURE__ */ jsxRuntime.jsx(
4505
- "div",
4506
- {
4507
- ...utils.mergeProps(overlayProps, dialogProps),
4508
- ref: panelRef,
4509
- className,
4510
- "aria-modal": "true",
4511
- children
4512
- }
4513
- );
4514
- };
4515
- ModalDrawerPanel.displayName = "ModalDrawerPanel";
4516
4583
  var HeadlessDrawerItem = React.forwardRef(
4517
4584
  ({
4518
4585
  href,
@@ -4530,7 +4597,6 @@ var HeadlessDrawerItem = React.forwardRef(
4530
4597
  ...restProps
4531
4598
  }, forwardedRef) => {
4532
4599
  const internalRef = React.useRef(null);
4533
- const { isFocusVisible, focusProps } = reactAria.useFocusRing();
4534
4600
  if (href) {
4535
4601
  const linkRef = forwardedRef ?? internalRef;
4536
4602
  const { linkProps } = reactAria.useLink(
@@ -4544,14 +4610,12 @@ var HeadlessDrawerItem = React.forwardRef(
4544
4610
  return /* @__PURE__ */ jsxRuntime.jsx(
4545
4611
  "a",
4546
4612
  {
4547
- ...utils.mergeProps(linkProps, focusProps, { onMouseDown }),
4613
+ ...utils.mergeProps(linkProps, { onMouseDown }),
4548
4614
  ref: linkRef,
4549
4615
  href,
4550
4616
  className,
4551
4617
  title,
4552
4618
  "aria-current": isActive ? "page" : void 0,
4553
- "data-focus-visible": isFocusVisible || void 0,
4554
- "data-active": isActive || void 0,
4555
4619
  children
4556
4620
  }
4557
4621
  );
@@ -4574,13 +4638,11 @@ var HeadlessDrawerItem = React.forwardRef(
4574
4638
  "button",
4575
4639
  {
4576
4640
  type: "button",
4577
- ...utils.mergeProps(buttonProps, focusProps, { onMouseDown }),
4641
+ ...utils.mergeProps(buttonProps, { onMouseDown }),
4578
4642
  ref: buttonRef,
4579
4643
  className,
4580
4644
  title,
4581
4645
  "aria-current": isActive ? "page" : void 0,
4582
- "data-focus-visible": isFocusVisible || void 0,
4583
- "data-active": isActive || void 0,
4584
4646
  children
4585
4647
  }
4586
4648
  );
@@ -4675,120 +4737,195 @@ var drawerVariants = classVarianceAuthority.cva(
4675
4737
  // Layout
4676
4738
  "fixed top-0 left-0 h-full",
4677
4739
  "flex flex-col overflow-y-auto",
4678
- // Stacking and shape
4740
+ // Width 360dp per MD3 spec
4741
+ "w-drawer",
4742
+ // Stacking
4679
4743
  "z-50",
4680
- "rounded-r-xl",
4681
- // Slide animation (transition applies to all open/closed state changes)
4682
- "transition-transform duration-medium4 ease-emphasized-decelerate",
4744
+ // Container padding — 12dp per MD3 nav drawer spec
4745
+ "px-3 py-3",
4683
4746
  // Focus outline removal (focus management handled by FocusScope / React Aria)
4684
- "outline-none",
4685
- // Padding for content spacing
4686
- "px-3"
4747
+ "outline-none"
4687
4748
  ],
4688
4749
  {
4689
4750
  variants: {
4690
4751
  /**
4691
- * Structural variant — drives surface color and elevation.
4692
- * - `standard`: inline nav panel, lower-elevation surface
4693
- * - `modal`: overlay dialog with elevation shadow
4752
+ * Structural variant — drives shape and elevation.
4753
+ *
4754
+ * - `standard`: flush left panel, square trailing edge, flat surface.
4755
+ * - `modal`: overlay dialog, 16dp trailing corner, shadow-elevation-1.
4694
4756
  */
4695
4757
  variant: {
4696
- standard: ["bg-surface-container-low"],
4697
- modal: ["bg-surface-container", "shadow-elevation-1"]
4758
+ standard: ["bg-surface-container-low", "rounded-none"],
4759
+ modal: ["bg-surface-container-low", "rounded-r-lg", "shadow-elevation-1"]
4698
4760
  },
4699
4761
  /**
4700
- * Open/closed state — drives translation.
4701
- * - `true`: drawer visible (`translate-x-0`)
4702
- * - `false`: drawer off-screen (`-translate-x-full`)
4762
+ * Open/closed state — drives translation for the STANDARD variant only.
4763
+ *
4764
+ * Standard slide: spatial on-screen property → spring-standard-default-spatial.
4765
+ * Modal enter/exit is handled externally via drawerAnimationVariants + portal gate.
4766
+ *
4767
+ * - `true`: translate-x-0 (visible)
4768
+ * - `false`: -translate-x-full (off-screen to the left)
4703
4769
  */
4704
4770
  open: {
4705
- true: ["translate-x-0"],
4706
- false: ["-translate-x-full"]
4707
- },
4708
- /**
4709
- * Icon-only compact mode — 80dp rail instead of 360dp drawer.
4710
- * - `true`: `w-20` (80dp), items centered
4711
- * - `false`: `w-drawer` (360dp), standard layout
4712
- */
4713
- iconOnly: {
4714
- true: ["w-20", "items-center"],
4715
- false: ["w-drawer"]
4771
+ true: [
4772
+ "translate-x-0",
4773
+ "transition-transform",
4774
+ "duration-spring-standard-default-spatial",
4775
+ "ease-spring-standard-default-spatial"
4776
+ ],
4777
+ false: [
4778
+ "-translate-x-full",
4779
+ "transition-transform",
4780
+ "duration-spring-standard-default-spatial",
4781
+ "ease-spring-standard-default-spatial"
4782
+ ]
4716
4783
  }
4717
4784
  },
4718
4785
  defaultVariants: {
4719
4786
  variant: "standard",
4720
- open: false,
4721
- iconOnly: false
4787
+ open: false
4722
4788
  }
4723
4789
  }
4724
4790
  );
4725
- var drawerItemVariants = classVarianceAuthority.cva(
4791
+ var drawerAnimationVariants = classVarianceAuthority.cva("", {
4792
+ variants: {
4793
+ animationState: {
4794
+ // Mount frame: invisible until animation starts
4795
+ entering: ["opacity-0"],
4796
+ // Entry animation: slide in from the left edge
4797
+ visible: ["animate-md-slide-in-left"],
4798
+ // Exit animation: slide out to the left
4799
+ exiting: ["animate-md-slide-out-left"],
4800
+ // Portal gate removes element; classes below act as a safety net
4801
+ exited: ["opacity-0", "pointer-events-none"]
4802
+ }
4803
+ },
4804
+ defaultVariants: {
4805
+ animationState: "entering"
4806
+ }
4807
+ });
4808
+ var drawerScrimAnimationVariants = classVarianceAuthority.cva(
4726
4809
  [
4727
- // Layout
4728
- "relative flex w-full items-center gap-3",
4729
- "h-14 px-4",
4730
- "rounded-full",
4731
- // Typography
4732
- "text-label-large",
4733
- // Interaction
4734
- "cursor-pointer select-none outline-none",
4735
- // State layer pseudo-element (z-[1] above active indicator)
4736
- "before:absolute before:inset-0 before:rounded-full before:z-[1]",
4737
- "before:transition-opacity before:duration-short2 before:ease-standard",
4738
- "before:opacity-0",
4739
- // Hover and focus visible state layers
4740
- "hover:before:opacity-8",
4741
- "focus-visible:before:opacity-12",
4742
- // Active pressed state
4743
- "active:before:opacity-12",
4744
- // Transition for color changes
4745
- "transition-colors duration-short2 ease-standard"
4810
+ "transition-opacity",
4811
+ "duration-spring-standard-fast-effects",
4812
+ "ease-spring-standard-fast-effects"
4746
4813
  ],
4747
4814
  {
4748
4815
  variants: {
4749
- /**
4750
- * Whether this item is the currently active destination.
4751
- *
4752
- * Active indicator is a 336dp pill rendered via `after:` pseudo-element
4753
- * per MD3 Navigation Drawer spec.
4754
- */
4755
- isActive: {
4756
- true: [
4757
- "text-on-secondary-container",
4758
- "before:bg-on-secondary-container",
4759
- // Active indicator — 336dp pill via after: pseudo
4760
- "after:absolute after:inset-0 after:mx-auto after:max-w-[336px]",
4761
- "after:rounded-full after:bg-secondary-container"
4762
- ],
4763
- false: ["bg-transparent", "text-on-surface-variant", "before:bg-on-surface-variant"]
4764
- },
4765
- /**
4766
- * Whether the item is disabled.
4767
- * Applies `opacity-38` per MD3 disabled state spec.
4768
- */
4769
- isDisabled: {
4770
- true: ["opacity-38 cursor-not-allowed pointer-events-none"],
4771
- false: []
4816
+ animationState: {
4817
+ entering: ["opacity-0"],
4818
+ visible: ["opacity-32"],
4819
+ exiting: ["opacity-0"],
4820
+ exited: ["opacity-0", "pointer-events-none"]
4772
4821
  }
4773
4822
  },
4774
4823
  defaultVariants: {
4775
- isActive: false,
4776
- isDisabled: false
4824
+ animationState: "entering"
4777
4825
  }
4778
4826
  }
4779
4827
  );
4780
- var scrimVariants = classVarianceAuthority.cva([
4828
+ var drawerItemVariants = classVarianceAuthority.cva([
4829
+ // Layout
4830
+ "relative flex w-full items-center",
4831
+ "h-14 pl-4 pr-6 gap-3",
4832
+ // Shape
4833
+ "rounded-full",
4834
+ // Typography — Label Large per MD3 spec (size via text-label-large, weight + tracking explicit)
4835
+ "text-label-large",
4836
+ "font-medium",
4837
+ "tracking-[0.1px]",
4838
+ // Interaction
4839
+ "cursor-pointer select-none outline-none",
4840
+ // Color transition (effects — no overshoot)
4841
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
4842
+ // Inactive content color (icon/label/badge inherit this via currentColor)
4843
+ "text-on-surface-variant",
4844
+ // Active content color — self-targeting data-[active]: (root is the group host)
4845
+ "data-[active]:text-on-secondary-container",
4846
+ // Disabled — self-targeting
4847
+ "data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed",
4848
+ "data-[disabled]:text-on-surface/38"
4849
+ ]);
4850
+ var drawerItemActiveIndicatorVariants = classVarianceAuthority.cva([
4851
+ "absolute inset-0 rounded-[inherit] pointer-events-none",
4852
+ "bg-secondary-container",
4853
+ // Effects transition for opacity — no overshoot
4854
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
4855
+ // Hidden when inactive; shown when active
4856
+ "opacity-0",
4857
+ "group-data-[active]/draweritem:opacity-100",
4858
+ // z-0: below state layer (z-[1]) and content (z-10)
4859
+ "z-0"
4860
+ ]);
4861
+ var drawerItemStateLayerVariants = classVarianceAuthority.cva([
4862
+ "absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
4863
+ // Effects transition — opacity must NOT overshoot
4864
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
4865
+ // Color: inactive uses on-surface-variant; active switches to on-secondary-container
4866
+ "bg-on-surface-variant",
4867
+ "group-data-[active]/draweritem:bg-on-secondary-container",
4868
+ // Hover: 8%
4869
+ "group-data-[hovered]/draweritem:opacity-8",
4870
+ // Focus-visible: 10% (MD3 focus state layer)
4871
+ "group-data-[focus-visible]/draweritem:opacity-10",
4872
+ // Pressed: 10%, doubled selector wins over hover at same cascade position
4873
+ "group-data-[pressed]/draweritem:group-data-[pressed]/draweritem:opacity-10",
4874
+ // No state layer when disabled
4875
+ "group-data-[disabled]/draweritem:hidden",
4876
+ // z-[1]: above active indicator (z-0), below focus ring and content
4877
+ "z-[1]"
4878
+ ]);
4879
+ var drawerItemFocusRingVariants = classVarianceAuthority.cva([
4880
+ "pointer-events-none absolute inset-0 rounded-[inherit]",
4881
+ "outline outline-2 -outline-offset-2 outline-secondary",
4882
+ // Effects transition — opacity must not overshoot
4883
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
4884
+ "opacity-0",
4885
+ "group-data-[focus-visible]/draweritem:opacity-100",
4886
+ // z-[2]: above state layer (z-[1]), below content (z-10)
4887
+ "z-[2]"
4888
+ ]);
4889
+ var drawerItemIconVariants = classVarianceAuthority.cva([
4890
+ "relative z-10 flex shrink-0 items-center justify-center",
4891
+ "h-6 w-6",
4892
+ // Color and transition inherited via currentColor from root
4893
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
4894
+ // Explicit disabled override — mirrors Menu icon (on-surface/38)
4895
+ "group-data-[disabled]/draweritem:text-on-surface/38"
4896
+ ]);
4897
+ var drawerItemLabelVariants = classVarianceAuthority.cva(["relative z-10 flex-1 min-w-0 truncate"]);
4898
+ var drawerItemBadgeVariants = classVarianceAuthority.cva([
4899
+ "relative z-10 shrink-0 ml-auto",
4900
+ "text-label-large",
4901
+ "font-medium",
4902
+ "tracking-[0.1px]",
4903
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
4904
+ ]);
4905
+ var drawerHeadlineVariants = classVarianceAuthority.cva([
4906
+ "px-4 pt-4 pb-1",
4907
+ "text-title-small",
4908
+ "font-medium",
4909
+ "tracking-[0.1px]",
4910
+ "text-on-surface-variant",
4911
+ "select-none"
4912
+ ]);
4913
+ var drawerScrimVariants = classVarianceAuthority.cva([
4781
4914
  "fixed inset-0 z-40",
4782
- "bg-scrim opacity-32",
4783
- "transition-opacity duration-short4 ease-standard"
4915
+ // NOTE: opacity is intentionally absent here — it is controlled per
4916
+ // animation state by drawerScrimAnimationVariants (opacity-0 / opacity-32)
4917
+ // to avoid tailwind-merge collapsing the classes during cn() composition.
4918
+ "bg-scrim"
4784
4919
  ]);
4785
4920
  var drawerSectionVariants = classVarianceAuthority.cva(["flex flex-col w-full"]);
4786
4921
  var drawerSectionHeaderVariants = classVarianceAuthority.cva([
4787
4922
  "px-4 pt-4 pb-2",
4788
- "text-title-small text-on-surface-variant",
4923
+ "text-title-small",
4924
+ "font-medium",
4925
+ "tracking-[0.1px]",
4926
+ "text-on-surface-variant",
4789
4927
  "select-none"
4790
4928
  ]);
4791
- classVarianceAuthority.cva(["border-t border-outline-variant", "mx-4 my-2"]);
4792
4929
  var DrawerSection = React.forwardRef(
4793
4930
  ({ header, children, showDivider = true, _isFirstSection = false, className }, ref) => {
4794
4931
  const shouldShowDivider = showDivider && !_isFirstSection;
@@ -4810,19 +4947,19 @@ var Drawer = React.forwardRef(
4810
4947
  children,
4811
4948
  className,
4812
4949
  disableRipple = false,
4813
- iconOnly = false,
4814
4950
  ...restProps
4815
4951
  }, ref) => {
4816
4952
  const isOpen = open ?? defaultOpen;
4953
+ const reducedMotion = useReducedMotion();
4817
4954
  const drawerPanelClass = cn(
4818
- drawerVariants({
4819
- variant,
4820
- open: isOpen,
4821
- iconOnly
4822
- }),
4955
+ drawerVariants({ variant, open: isOpen }),
4956
+ // Suppress spring transition when user has requested reduced motion
4957
+ reducedMotion && "transition-none",
4823
4958
  className
4824
4959
  );
4825
- const scrimClass = scrimVariants();
4960
+ const scrimClass = drawerScrimVariants();
4961
+ const getAnimationClassName = reducedMotion ? (_state) => "" : (state) => drawerAnimationVariants({ animationState: state });
4962
+ const getScrimAnimationClassName = reducedMotion ? (_state) => "" : (state) => drawerScrimAnimationVariants({ animationState: state });
4826
4963
  let foundFirstSection = false;
4827
4964
  const processedChildren = React__default.default.Children.map(children, (child) => {
4828
4965
  if (React__default.default.isValidElement(child) && child.type === DrawerSection) {
@@ -4835,7 +4972,7 @@ var Drawer = React.forwardRef(
4835
4972
  }
4836
4973
  return child;
4837
4974
  });
4838
- return /* @__PURE__ */ jsxRuntime.jsx(DrawerIconOnlyContext.Provider, { value: iconOnly, children: /* @__PURE__ */ jsxRuntime.jsx(
4975
+ return /* @__PURE__ */ jsxRuntime.jsx(
4839
4976
  HeadlessDrawer,
4840
4977
  {
4841
4978
  ref,
@@ -4846,153 +4983,99 @@ var Drawer = React.forwardRef(
4846
4983
  "aria-label": ariaLabel,
4847
4984
  className: drawerPanelClass,
4848
4985
  scrimClassName: scrimClass,
4986
+ getAnimationClassName,
4987
+ getScrimAnimationClassName,
4849
4988
  disableRipple,
4850
- iconOnly,
4851
4989
  ...restProps,
4852
4990
  children: processedChildren
4853
4991
  }
4854
- ) });
4992
+ );
4855
4993
  }
4856
4994
  );
4857
4995
  Drawer.displayName = "Drawer";
4858
- var badgeAppearance = [
4859
- // ── Shape ─────────────────────────────────────────────────────────────────────
4860
- "flex items-center justify-center",
4861
- "rounded-full",
4862
- // ── Large (count) sizing — base defaults ──────────────────────────────────────
4863
- // Height 16dp, min-width 16dp, horizontal padding 4dp
4864
- "h-4 min-w-4 px-1",
4865
- // ── Color — error role (only MD3-spec role for badges) ────────────────────────
4866
- "bg-error text-on-error",
4867
- // ── Typography — label-small, tight leading, tabular numbers ──────────────────
4868
- "text-label-small leading-none tabular-nums",
4869
- // ── Visibility (runtime flag) ──────────────────────────────────────────────────
4870
- // Base: fully visible
4871
- "scale-100",
4872
- // data-invisible: scale to zero (visually hidden; aria-label still readable by SR)
4873
- "data-[invisible]:scale-0",
4874
- // ── Dot content flag overrides (placed last — cascade wins over base sizing) ───
4875
- // Clear out the count-pill sizing, set 6dp circle
4876
- "data-[dot]:size-1.5",
4877
- "data-[dot]:min-w-0",
4878
- "data-[dot]:p-0",
4879
- "data-[dot]:text-[0]"
4880
- // suppress any stray text rendering on dot
4881
- ];
4882
- var badgeVariants2 = classVarianceAuthority.cva([
4883
- // ── Anchored placement — badge center on host's top-right corner ──────────────
4884
- // top-0 right-0 places the badge's own top-right at the host's top-right,
4885
- // then the 1/2-element translate moves the badge center onto that corner.
4886
- // Host-size-agnostic: works for any wrapped element (icon, avatar, nav chip).
4887
- "absolute top-0 right-0 -translate-y-1/2 translate-x-1/2",
4888
- ...badgeAppearance
4889
- ]);
4890
- var badgeStaticVariants = classVarianceAuthority.cva(["inline-flex", ...badgeAppearance]);
4891
- function isBadgeConfig(badge) {
4892
- return typeof badge === "object" && badge !== null && !React.isValidElement(badge) && "count" in badge;
4893
- }
4894
- function getBadgeDisplayValue(count, max) {
4895
- if (count === void 0) return "";
4896
- return count > max ? `${max}+` : count.toString();
4897
- }
4898
- function getBadgeAriaLabel(count) {
4899
- return count === void 0 ? "New" : `${count} notifications`;
4900
- }
4901
4996
  var DrawerItem = React.forwardRef(
4902
4997
  ({
4903
4998
  href,
4904
4999
  icon,
4905
5000
  label,
4906
5001
  badge,
4907
- secondaryText,
4908
5002
  isActive = false,
4909
5003
  isDisabled = false,
4910
5004
  disableRipple = false,
4911
5005
  className,
4912
- onPress,
4913
- onPressStart,
4914
- onPressEnd,
4915
- onPressChange,
4916
- onPressUp,
5006
+ // All remaining props (onPress, onPressStart, onPressEnd, etc.) stay in
5007
+ // restProps and are passed into mergeProps — mirrors the Button pattern.
4917
5008
  ...restProps
4918
5009
  }, ref) => {
4919
- const isItemDisabled = isDisabled;
4920
- const isIconOnly = React.useContext(DrawerIconOnlyContext);
5010
+ const [isPressed, setIsPressed] = React.useState(false);
5011
+ const handlePressStart = React.useCallback(() => setIsPressed(true), []);
5012
+ const handlePressEnd = React.useCallback(() => setIsPressed(false), []);
5013
+ const { isHovered, hoverProps } = reactAria.useHover({ isDisabled });
5014
+ const { isFocusVisible, focusProps } = reactAria.useFocusRing();
4921
5015
  const { onMouseDown: handleRipple, ripples } = useRipple({
4922
- disabled: isItemDisabled || disableRipple
5016
+ disabled: isDisabled || disableRipple
4923
5017
  });
4924
- const renderBadge = () => {
4925
- if (!badge) return null;
4926
- if (isBadgeConfig(badge)) {
4927
- const max = 999;
4928
- const isDot = badge.count === void 0;
4929
- const displayValue = getBadgeDisplayValue(badge.count, max);
4930
- const ariaLabel = getBadgeAriaLabel(badge.count);
4931
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10 ml-auto flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsxRuntime.jsx(
4932
- "span",
4933
- {
4934
- role: "status",
4935
- "aria-label": ariaLabel,
4936
- "data-dot": isDot ? "" : void 0,
4937
- className: cn(badgeStaticVariants()),
4938
- children: displayValue
4939
- }
4940
- ) });
4941
- }
4942
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10 ml-auto flex shrink-0 items-center pr-2", "aria-hidden": "true", children: badge });
4943
- };
5018
+ const mergedInteractionProps = reactAria.mergeProps(
5019
+ hoverProps,
5020
+ focusProps,
5021
+ { onPressStart: handlePressStart, onPressEnd: handlePressEnd },
5022
+ restProps
5023
+ );
4944
5024
  return /* @__PURE__ */ jsxRuntime.jsxs(
4945
5025
  HeadlessDrawerItem,
4946
5026
  {
4947
- ...restProps,
5027
+ ...mergedInteractionProps,
4948
5028
  ref,
4949
5029
  ...href !== void 0 ? { href } : {},
4950
5030
  isActive,
4951
- ...isItemDisabled !== void 0 ? { isDisabled: isItemDisabled } : {},
4952
- ...onPress !== void 0 ? { onPress } : {},
4953
- ...onPressStart !== void 0 ? { onPressStart } : {},
4954
- ...onPressEnd !== void 0 ? { onPressEnd } : {},
4955
- ...onPressChange !== void 0 ? { onPressChange } : {},
4956
- ...onPressUp !== void 0 ? { onPressUp } : {},
5031
+ ...isDisabled !== void 0 ? { isDisabled } : {},
4957
5032
  onMouseDown: handleRipple,
4958
- title: isIconOnly ? label : void 0,
5033
+ ...getInteractionDataAttributes({
5034
+ isHovered,
5035
+ isFocusVisible,
5036
+ isPressed,
5037
+ isDisabled
5038
+ }),
5039
+ "data-active": isActive ? "" : void 0,
4959
5040
  className: cn(
4960
- drawerItemVariants({
4961
- isActive,
4962
- isDisabled: isItemDisabled
4963
- }),
5041
+ drawerItemVariants(),
5042
+ // group/draweritem: enables group-data-[x]/draweritem selectors in all slots
5043
+ "group/draweritem",
4964
5044
  className
4965
5045
  ),
4966
5046
  children: [
4967
- ripples,
4968
- icon && /* @__PURE__ */ jsxRuntime.jsx(
5047
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: drawerItemActiveIndicatorVariants() }),
5048
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: drawerItemStateLayerVariants() }),
5049
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: drawerItemFocusRingVariants() }),
5050
+ /* @__PURE__ */ jsxRuntime.jsx(
4969
5051
  "span",
4970
5052
  {
4971
- className: "relative z-10 flex shrink-0 items-center justify-center",
5053
+ className: "pointer-events-none absolute inset-0 z-[3] overflow-hidden rounded-[inherit]",
4972
5054
  "aria-hidden": "true",
4973
- children: icon
5055
+ children: ripples
4974
5056
  }
4975
5057
  ),
4976
- /* @__PURE__ */ jsxRuntime.jsxs(
5058
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: drawerItemIconVariants(), children: icon }),
5059
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: drawerItemLabelVariants(), children: label }),
5060
+ badge !== void 0 && badge !== null && /* @__PURE__ */ jsxRuntime.jsx(
4977
5061
  "span",
4978
5062
  {
4979
- className: cn(
4980
- "relative z-10 flex min-w-0 flex-1 flex-col text-left",
4981
- isIconOnly && "hidden"
4982
- ),
4983
- children: [
4984
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label }),
4985
- secondaryText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-body-small truncate opacity-70", children: secondaryText })
4986
- ]
5063
+ role: "status",
5064
+ "aria-label": typeof badge === "number" ? `${badge} notifications` : String(badge),
5065
+ className: drawerItemBadgeVariants(),
5066
+ children: badge
4987
5067
  }
4988
- ),
4989
- !isIconOnly && renderBadge()
5068
+ )
4990
5069
  ]
4991
5070
  }
4992
5071
  );
4993
5072
  }
4994
5073
  );
4995
5074
  DrawerItem.displayName = "DrawerItem";
5075
+ var DrawerHeadline = React.forwardRef(
5076
+ ({ children, className, ...restProps }, ref) => /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn(drawerHeadlineVariants(), className), ...restProps, children })
5077
+ );
5078
+ DrawerHeadline.displayName = "DrawerHeadline";
4996
5079
  var progressContainerVariants = classVarianceAuthority.cva(["inline-flex", "flex-col", "gap-1"], {
4997
5080
  variants: {
4998
5081
  type: {
@@ -10030,6 +10113,39 @@ var BadgeHeadless = React.forwardRef(
10030
10113
  }
10031
10114
  );
10032
10115
  BadgeHeadless.displayName = "BadgeHeadless";
10116
+ var badgeAppearance = [
10117
+ // ── Shape ─────────────────────────────────────────────────────────────────────
10118
+ "flex items-center justify-center",
10119
+ "rounded-full",
10120
+ // ── Large (count) sizing — base defaults ──────────────────────────────────────
10121
+ // Height 16dp, min-width 16dp, horizontal padding 4dp
10122
+ "h-4 min-w-4 px-1",
10123
+ // ── Color — error role (only MD3-spec role for badges) ────────────────────────
10124
+ "bg-error text-on-error",
10125
+ // ── Typography — label-small, tight leading, tabular numbers ──────────────────
10126
+ "text-label-small leading-none tabular-nums",
10127
+ // ── Visibility (runtime flag) ──────────────────────────────────────────────────
10128
+ // Base: fully visible
10129
+ "scale-100",
10130
+ // data-invisible: scale to zero (visually hidden; aria-label still readable by SR)
10131
+ "data-[invisible]:scale-0",
10132
+ // ── Dot content flag overrides (placed last — cascade wins over base sizing) ───
10133
+ // Clear out the count-pill sizing, set 6dp circle
10134
+ "data-[dot]:size-1.5",
10135
+ "data-[dot]:min-w-0",
10136
+ "data-[dot]:p-0",
10137
+ "data-[dot]:text-[0]"
10138
+ // suppress any stray text rendering on dot
10139
+ ];
10140
+ var badgeVariants2 = classVarianceAuthority.cva([
10141
+ // ── Anchored placement — badge center on host's top-right corner ──────────────
10142
+ // top-0 right-0 places the badge's own top-right at the host's top-right,
10143
+ // then the 1/2-element translate moves the badge center onto that corner.
10144
+ // Host-size-agnostic: works for any wrapped element (icon, avatar, nav chip).
10145
+ "absolute top-0 right-0 -translate-y-1/2 translate-x-1/2",
10146
+ ...badgeAppearance
10147
+ ]);
10148
+ classVarianceAuthority.cva(["inline-flex", ...badgeAppearance]);
10033
10149
  var getDisplayValue = (count, max) => {
10034
10150
  if (count === void 0) return "";
10035
10151
  return count > max ? `${max}+` : count.toString();
@@ -15577,7 +15693,7 @@ var modeToggleStateLayerVariants = classVarianceAuthority.cva([
15577
15693
  "group-data-[focus-visible]/mode-toggle:opacity-10",
15578
15694
  "group-data-[pressed]/mode-toggle:opacity-10"
15579
15695
  ]);
15580
- var scrimVariants2 = classVarianceAuthority.cva([
15696
+ var scrimVariants = classVarianceAuthority.cva([
15581
15697
  "fixed inset-0 z-40",
15582
15698
  "bg-scrim opacity-32",
15583
15699
  "transition-opacity duration-medium2 ease-standard"
@@ -16320,7 +16436,7 @@ var DatePickerModalStyled = React.forwardRef(
16320
16436
  !reducedMotion && MODAL_DIALOG_MOTION,
16321
16437
  className
16322
16438
  ),
16323
- scrimClassName: cn(scrimVariants2()),
16439
+ scrimClassName: cn(scrimVariants()),
16324
16440
  slots: {
16325
16441
  CellComponent: StyledCalendarCell,
16326
16442
  NavButtonComponent: StyledNavButton,
@@ -16770,7 +16886,7 @@ var DatePickerModalInputStyled = React.forwardRef(
16770
16886
  MODAL_INPUT_CONTENT_STRUCTURAL,
16771
16887
  className
16772
16888
  ),
16773
- scrimClassName: cn(scrimVariants2()),
16889
+ scrimClassName: cn(scrimVariants()),
16774
16890
  ActionButtonComponent: StyledActionButton
16775
16891
  }
16776
16892
  );
@@ -16928,7 +17044,8 @@ exports.DialogHeadline = DialogHeadline;
16928
17044
  exports.Divider = Divider;
16929
17045
  exports.DividerHeadless = DividerHeadless;
16930
17046
  exports.Drawer = Drawer;
16931
- exports.DrawerIconOnlyContext = DrawerIconOnlyContext;
17047
+ exports.DrawerContext = DrawerContext;
17048
+ exports.DrawerHeadline = DrawerHeadline;
16932
17049
  exports.DrawerItem = DrawerItem;
16933
17050
  exports.DrawerSection = DrawerSection;
16934
17051
  exports.FAB = FAB;
@@ -17051,6 +17168,20 @@ exports.dockedFieldGroupVariants = dockedFieldGroupVariants;
17051
17168
  exports.dockedLabelVariants = dockedLabelVariants;
17052
17169
  exports.dockedTriggerStateLayerVariants = dockedTriggerStateLayerVariants;
17053
17170
  exports.dockedTriggerVariants = dockedTriggerVariants;
17171
+ exports.drawerAnimationVariants = drawerAnimationVariants;
17172
+ exports.drawerHeadlineVariants = drawerHeadlineVariants;
17173
+ exports.drawerItemActiveIndicatorVariants = drawerItemActiveIndicatorVariants;
17174
+ exports.drawerItemBadgeVariants = drawerItemBadgeVariants;
17175
+ exports.drawerItemFocusRingVariants = drawerItemFocusRingVariants;
17176
+ exports.drawerItemIconVariants = drawerItemIconVariants;
17177
+ exports.drawerItemLabelVariants = drawerItemLabelVariants;
17178
+ exports.drawerItemStateLayerVariants = drawerItemStateLayerVariants;
17179
+ exports.drawerItemVariants = drawerItemVariants;
17180
+ exports.drawerScrimAnimationVariants = drawerScrimAnimationVariants;
17181
+ exports.drawerScrimVariants = drawerScrimVariants;
17182
+ exports.drawerSectionHeaderVariants = drawerSectionHeaderVariants;
17183
+ exports.drawerSectionVariants = drawerSectionVariants;
17184
+ exports.drawerVariants = drawerVariants;
17054
17185
  exports.fabMenuItemFocusRingVariants = fabMenuItemFocusRingVariants;
17055
17186
  exports.fabMenuItemIconVariants = fabMenuItemIconVariants;
17056
17187
  exports.fabMenuItemLabelVariants = fabMenuItemLabelVariants;
@@ -17086,7 +17217,7 @@ exports.pxToRem = pxToRem;
17086
17217
  exports.remToPx = remToPx;
17087
17218
  exports.rgbToHex = rgbToHex;
17088
17219
  exports.richTooltipVariants = richTooltipVariants;
17089
- exports.scrimVariants = scrimVariants2;
17220
+ exports.scrimVariants = scrimVariants;
17090
17221
  exports.searchBarAvatarVariants = searchBarAvatarVariants;
17091
17222
  exports.searchBarFocusRingVariants = searchBarFocusRingVariants;
17092
17223
  exports.searchBarInputVariants = searchBarInputVariants;