@tinybigui/react 0.4.1 → 0.5.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.js CHANGED
@@ -2,10 +2,10 @@ import { clsx } from 'clsx';
2
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 React, { forwardRef, useRef, createContext, useId, useState, useCallback, useEffect, useContext, useMemo, useLayoutEffect, Children, isValidElement, cloneElement } from 'react';
5
+ import React, { forwardRef, useRef, createContext, useState, useCallback, useId, useMemo, useEffect, useContext, useLayoutEffect, 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, useHover, useRadioGroup, useRadio, useTabList, useTab, useTabPanel, FocusScope, usePreventScroll, useDialog, useOverlay, useLink, useSeparator, useProgressBar, useToggleButton, useListBox, useOption, useSearchField, useSlider, useDatePicker, useLocale, useDateField, useSliderThumb, useRangeCalendar, useCalendar, usePopover, DismissButton, useDateSegment, useCalendarGrid, useCalendarCell, useTooltipTrigger, useTooltip, useOverlayPosition } from 'react-aria';
8
+ import { useButton, useHover, useFocusRing, mergeProps as mergeProps$1, useTextField, useCheckbox, VisuallyHidden, useSwitch, useRadioGroup, useRadio, useTabList, useTab, useTabPanel, FocusScope, usePreventScroll, useDialog, useOverlay, useLink, useSeparator, useProgressBar, useToggleButton, useListBox, useOption, useSearchField, useSlider, useDatePicker, useLocale, useDateField, useSliderThumb, useRangeCalendar, useCalendar, usePopover, DismissButton, useDateSegment, useCalendarGrid, useCalendarCell, useTooltipTrigger, useTooltip, useOverlayPosition } from 'react-aria';
9
9
  import { mergeProps, filterDOMProps } from '@react-aria/utils';
10
10
  import { useToggleState, useRadioGroupState, useTabListState, Item, useOverlayTriggerState, useListState, useSearchFieldState, useMenuTriggerState, useSliderState, useDatePickerState, useDateFieldState, useRangeCalendarState, useCalendarState, useTooltipTriggerState } from 'react-stately';
11
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';
@@ -421,218 +421,206 @@ var ButtonHeadless = forwardRef(
421
421
  ButtonHeadless.displayName = "ButtonHeadless";
422
422
  var buttonVariants = cva(
423
423
  [
424
- // Base classes (always applied)
425
- "relative inline-flex items-center justify-center cursor-pointer",
426
- "overflow-hidden rounded-full font-medium",
427
- // Split MD3 transition: spatial (border-radius) uses expressive spring with overshoot;
428
- // effects (color/bg/shadow) use standard effects spring — no overshoot allowed on color.
424
+ // Layout + shape — NO overflow-hidden here (see note above)
425
+ "relative inline-flex items-center justify-center",
426
+ "rounded-full cursor-pointer select-none",
427
+ // Split MD3 transition: spatial (border-radius) expressive spring;
428
+ // effects (color/bg/shadow) standard effects spring.
429
429
  "btn-transition",
430
- "tracking-[0.1px]",
431
- // MD3 spec: +0.1px letter-spacing for label-large
432
- "focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2"
430
+ // Disabled — self-targeting data-[x]: selectors
431
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none"
433
432
  ],
434
433
  {
435
434
  variants: {
436
435
  /**
437
- * Button variant (MD3 specification)
436
+ * Button variant (MD3 specification — strict, no color override)
437
+ *
438
+ * Elevation per state follows _md-comp-*-button.scss tokens:
439
+ * Filled/Tonal hover→level-1, focus/pressed→level-0
440
+ * Elevated base→level-1, hover→level-2, focus/pressed→level-1
441
+ * Outlined/Text no elevation
438
442
  */
439
443
  variant: {
440
- filled: "shadow-none hover:shadow-elevation-1",
441
- // MD3: gains elevation on hover
442
- outlined: "bg-transparent border border-outline-variant",
443
- tonal: "",
444
- elevated: "shadow-elevation-1 hover:shadow-elevation-2",
445
- // MD3: level 1 → level 2 on hover
446
- text: "bg-transparent"
447
- },
448
- /**
449
- * Color scheme (MD3 color roles)
450
- */
451
- color: {
452
- primary: "",
453
- secondary: "",
454
- tertiary: "",
455
- error: ""
444
+ /**
445
+ * Filled highest emphasis.
446
+ * MD3: container=primary, label=on-primary, state-layer=on-primary
447
+ * Elevation: 0 base → 1 hover → 0 focus → 0 pressed
448
+ */
449
+ filled: [
450
+ "bg-primary text-on-primary shadow-none",
451
+ // Hover: gains level-1 elevation
452
+ "group-data-[hovered]/button:shadow-elevation-1",
453
+ // Focus/pressed: shadow must explicitly return to level-0
454
+ // (doubled attribute selector → higher specificity than hover)
455
+ "group-data-[focus-visible]/button:shadow-none",
456
+ "group-data-[pressed]/button:group-data-[pressed]/button:shadow-none",
457
+ // Disabled overrides
458
+ "group-data-[disabled]/button:bg-on-surface/12",
459
+ "group-data-[disabled]/button:text-on-surface/38",
460
+ "group-data-[disabled]/button:shadow-none"
461
+ ],
462
+ /**
463
+ * Outlined — medium emphasis. Transparent with border.
464
+ * MD3: container=transparent, outline=outline, label=primary, state-layer=primary
465
+ * Elevation: always 0
466
+ */
467
+ outlined: [
468
+ "bg-transparent border border-outline text-primary",
469
+ // Disabled overrides
470
+ "group-data-[disabled]/button:border-on-surface/12",
471
+ "group-data-[disabled]/button:text-on-surface/38"
472
+ ],
473
+ /**
474
+ * Tonal — secondary emphasis.
475
+ * MD3 name: "Filled tonal". container=secondary-container, label=on-secondary-container
476
+ * Elevation: 0 base → 1 hover → 0 focus → 0 pressed
477
+ */
478
+ tonal: [
479
+ "bg-secondary-container text-on-secondary-container shadow-none",
480
+ // Hover: gains level-1 elevation (same as filled)
481
+ "group-data-[hovered]/button:shadow-elevation-1",
482
+ // Focus/pressed: return to level-0
483
+ "group-data-[focus-visible]/button:shadow-none",
484
+ "group-data-[pressed]/button:group-data-[pressed]/button:shadow-none",
485
+ // Disabled overrides
486
+ "group-data-[disabled]/button:bg-on-surface/12",
487
+ "group-data-[disabled]/button:text-on-surface/38",
488
+ "group-data-[disabled]/button:shadow-none"
489
+ ],
490
+ /**
491
+ * Elevated — separation via shadow.
492
+ * MD3: container=surface-container-low, label=primary
493
+ * Elevation: 1 base → 2 hover → 1 focus → 1 pressed
494
+ */
495
+ elevated: [
496
+ "bg-surface-container-low text-primary shadow-elevation-1",
497
+ // Hover: gains extra elevation
498
+ "group-data-[hovered]/button:shadow-elevation-2",
499
+ // Focus/pressed: return to base level-1
500
+ // (doubled selector wins over single hover selector at same cascade position)
501
+ "group-data-[focus-visible]/button:shadow-elevation-1",
502
+ "group-data-[pressed]/button:group-data-[pressed]/button:shadow-elevation-1",
503
+ // Disabled overrides
504
+ "group-data-[disabled]/button:bg-on-surface/12",
505
+ "group-data-[disabled]/button:text-on-surface/38",
506
+ "group-data-[disabled]/button:shadow-none"
507
+ ],
508
+ /**
509
+ * Text — lowest emphasis.
510
+ * MD3: container=transparent, label=primary, state-layer=primary
511
+ * Elevation: always 0
512
+ */
513
+ text: [
514
+ "bg-transparent text-primary",
515
+ // Disabled overrides
516
+ "group-data-[disabled]/button:text-on-surface/38"
517
+ ]
456
518
  },
457
519
  /**
458
520
  * Button size
521
+ * MD3 spec: small=32dp, medium=40dp, large=56dp
522
+ * Padding: small=16dp, medium=24dp, large=32dp
523
+ * Text variant uses reduced padding: small=12dp, medium=12dp
459
524
  */
460
525
  size: {
461
- small: "h-8 px-4 text-sm gap-2",
462
- medium: "h-10 px-6 text-sm gap-2",
463
- large: "h-12 px-8 text-base gap-3"
526
+ small: "h-8 px-4 gap-1 text-label-medium tracking-[0.1px]",
527
+ medium: "h-10 px-6 gap-2 text-label-large tracking-[0.1px]",
528
+ large: "h-14 px-8 gap-2 text-title-medium"
464
529
  },
465
530
  /**
466
- * Full width variant
531
+ * Full width button (spans container)
467
532
  */
468
533
  fullWidth: {
469
534
  true: "w-full",
470
535
  false: ""
471
- },
472
- /**
473
- * Disabled state (MD3 spec: container 12% opacity, content 38% opacity)
474
- */
475
- disabled: {
476
- true: [
477
- "pointer-events-none cursor-not-allowed",
478
- "bg-on-surface/12",
479
- // MD3: disabled container uses on-surface at 12%
480
- "text-on-surface/38",
481
- // MD3: disabled text/icons use on-surface at 38%
482
- "border-on-surface/12",
483
- // For outlined variant
484
- "shadow-none"
485
- // Remove elevation when disabled
486
- ],
487
- false: ""
488
- },
489
- /**
490
- * Loading state
491
- */
492
- loading: {
493
- true: "cursor-wait",
494
- false: ""
495
536
  }
496
537
  },
497
538
  /**
498
- * Compound variants - combinations of variant + color
539
+ * Compound variants for text variant reduced padding per size
540
+ * MD3: text buttons use 12dp padding (px-3) instead of standard padding
499
541
  */
500
542
  compoundVariants: [
501
- // ====================
502
- // FILLED VARIANTS
503
- // ====================
504
- {
505
- variant: "filled",
506
- color: "primary",
507
- className: "bg-primary text-on-primary"
508
- },
509
- {
510
- variant: "filled",
511
- color: "secondary",
512
- className: "bg-secondary text-on-secondary"
513
- },
514
- {
515
- variant: "filled",
516
- color: "tertiary",
517
- className: "bg-tertiary text-on-tertiary"
518
- },
519
- {
520
- variant: "filled",
521
- color: "error",
522
- className: "bg-error text-on-error"
523
- },
524
- // ====================
525
- // OUTLINED VARIANTS
526
- // ====================
527
- {
528
- variant: "outlined",
529
- color: "primary",
530
- className: "text-primary"
531
- },
532
- {
533
- variant: "outlined",
534
- color: "secondary",
535
- className: "text-secondary"
536
- },
537
- {
538
- variant: "outlined",
539
- color: "tertiary",
540
- className: "text-tertiary"
541
- },
542
- {
543
- variant: "outlined",
544
- color: "error",
545
- className: "text-error"
546
- },
547
- // ====================
548
- // TONAL VARIANTS
549
- // ====================
550
- {
551
- variant: "tonal",
552
- color: "primary",
553
- className: "bg-primary-container text-on-primary-container"
554
- },
555
- {
556
- variant: "tonal",
557
- color: "secondary",
558
- className: "bg-secondary-container text-on-secondary-container"
559
- },
560
- {
561
- variant: "tonal",
562
- color: "tertiary",
563
- className: "bg-tertiary-container text-on-tertiary-container"
564
- },
565
- {
566
- variant: "tonal",
567
- color: "error",
568
- className: "bg-error-container text-on-error-container"
569
- },
570
- // ====================
571
- // ELEVATED VARIANTS
572
- // ====================
573
- {
574
- variant: "elevated",
575
- color: "primary",
576
- className: "bg-surface-container-low text-primary"
577
- },
578
- {
579
- variant: "elevated",
580
- color: "secondary",
581
- className: "bg-surface-container-low text-secondary"
582
- },
583
- {
584
- variant: "elevated",
585
- color: "tertiary",
586
- className: "bg-surface-container-low text-tertiary"
587
- },
588
- {
589
- variant: "elevated",
590
- color: "error",
591
- className: "bg-surface-container-low text-error"
592
- },
593
- // ====================
594
- // TEXT VARIANTS
595
- // ====================
596
- {
597
- variant: "text",
598
- color: "primary",
599
- className: "text-primary hover:bg-primary/[0.08]"
600
- // MD3: text buttons gain primary color at 8% opacity on hover
601
- },
602
- {
603
- variant: "text",
604
- color: "secondary",
605
- className: "text-secondary hover:bg-secondary/[0.08]"
606
- // MD3: text buttons gain secondary color at 8% opacity on hover
607
- },
608
- {
609
- variant: "text",
610
- color: "tertiary",
611
- className: "text-tertiary hover:bg-tertiary/[0.08]"
612
- // MD3: text buttons gain tertiary color at 8% opacity on hover
613
- },
614
- {
615
- variant: "text",
616
- color: "error",
617
- className: "text-error hover:bg-error/[0.08]"
618
- // MD3: text buttons gain error color at 8% opacity on hover
619
- }
543
+ { variant: "text", size: "small", className: "px-3" },
544
+ { variant: "text", size: "medium", className: "px-3" },
545
+ { variant: "text", size: "large", className: "px-4" }
620
546
  ],
621
- /**
622
- * Default variants
623
- */
624
547
  defaultVariants: {
625
548
  variant: "filled",
626
- color: "primary",
627
549
  size: "medium",
628
- fullWidth: false,
629
- disabled: false,
630
- loading: false
550
+ fullWidth: false
631
551
  }
632
552
  }
633
553
  );
554
+ var buttonStateLayerVariants = cva(
555
+ [
556
+ "absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
557
+ // Effects transition for opacity — standard spring, no overshoot
558
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
559
+ // Hover: 8%
560
+ "group-data-[hovered]/button:opacity-8",
561
+ // Focus: 10%
562
+ "group-data-[focus-visible]/button:opacity-10",
563
+ // Pressed: 10%, doubled selector wins over hover
564
+ "group-data-[pressed]/button:group-data-[pressed]/button:opacity-10",
565
+ // No state layer when disabled
566
+ "group-data-[disabled]/button:hidden"
567
+ ],
568
+ {
569
+ variants: {
570
+ variant: {
571
+ filled: "bg-on-primary",
572
+ outlined: "bg-primary",
573
+ tonal: "bg-on-secondary-container",
574
+ elevated: "bg-primary",
575
+ text: "bg-primary"
576
+ }
577
+ },
578
+ defaultVariants: { variant: "filled" }
579
+ }
580
+ );
581
+ var buttonFocusRingVariants = cva([
582
+ "pointer-events-none absolute inset-[-3px] rounded-full",
583
+ "outline outline-2 outline-offset-0 outline-secondary",
584
+ // Effects transition — opacity change must not overshoot
585
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
586
+ "opacity-0",
587
+ "group-data-[focus-visible]/button:opacity-100"
588
+ ]);
589
+ var buttonIconVariants = cva(
590
+ [
591
+ "relative z-10 inline-flex shrink-0 items-center justify-center",
592
+ "size-[18px]",
593
+ // Color transition uses effects token (no spatial overshoot on color)
594
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
595
+ ],
596
+ {
597
+ variants: {
598
+ hidden: {
599
+ true: "invisible",
600
+ false: ""
601
+ }
602
+ },
603
+ defaultVariants: { hidden: false }
604
+ }
605
+ );
606
+ var buttonLabelVariants = cva(["relative z-10 inline-flex items-center"]);
607
+ var QUERY = "(prefers-reduced-motion: reduce)";
608
+ function useReducedMotion() {
609
+ const [reduced, setReduced] = useState(() => {
610
+ if (typeof window === "undefined") return false;
611
+ return window.matchMedia(QUERY).matches;
612
+ });
613
+ useEffect(() => {
614
+ const mql = window.matchMedia(QUERY);
615
+ const handler = (e) => setReduced(e.matches);
616
+ mql.addEventListener("change", handler);
617
+ return () => mql.removeEventListener("change", handler);
618
+ }, []);
619
+ return reduced;
620
+ }
634
621
  function useRipple(options = {}) {
635
622
  const { disabled = false, color = "currentColor", duration = 450 } = options;
623
+ const prefersReducedMotion = useReducedMotion();
636
624
  const [ripples, setRipples] = useState([]);
637
625
  const rippleKeyCounter = useRef(0);
638
626
  const timersRef = useRef([]);
@@ -643,7 +631,7 @@ function useRipple(options = {}) {
643
631
  }, []);
644
632
  const onMouseDown = useCallback(
645
633
  (event) => {
646
- if (disabled) return;
634
+ if (disabled || prefersReducedMotion) return;
647
635
  const element = event.currentTarget;
648
636
  const rect = element.getBoundingClientRect();
649
637
  const x = event.clientX - rect.left;
@@ -659,9 +647,9 @@ function useRipple(options = {}) {
659
647
  }, duration);
660
648
  timersRef.current.push(timer);
661
649
  },
662
- [disabled, duration]
650
+ [disabled, duration, prefersReducedMotion]
663
651
  );
664
- const rippleElements = disabled ? null : /* @__PURE__ */ jsx(
652
+ const rippleElements = disabled || prefersReducedMotion ? null : /* @__PURE__ */ jsx(
665
653
  "span",
666
654
  {
667
655
  "data-ripple-container": true,
@@ -669,7 +657,7 @@ function useRipple(options = {}) {
669
657
  children: ripples.map((ripple) => /* @__PURE__ */ jsx(
670
658
  "span",
671
659
  {
672
- className: "animate-ripple absolute rounded-full opacity-12",
660
+ className: "animate-md-ripple absolute rounded-full opacity-12",
673
661
  style: {
674
662
  left: ripple.x,
675
663
  top: ripple.y,
@@ -761,7 +749,7 @@ var Spinner = () => /* @__PURE__ */ jsxs(
761
749
  {
762
750
  role: "progressbar",
763
751
  "aria-label": "Loading",
764
- className: "h-4 w-4 animate-spin",
752
+ className: "relative z-10 h-[18px] w-[18px] animate-spin",
765
753
  xmlns: "http://www.w3.org/2000/svg",
766
754
  fill: "none",
767
755
  viewBox: "0 0 24 24",
@@ -782,7 +770,6 @@ var Button = forwardRef(
782
770
  ({
783
771
  // Variant props (CVA)
784
772
  variant = "filled",
785
- color = "primary",
786
773
  size = "medium",
787
774
  fullWidth = false,
788
775
  // Content props
@@ -795,64 +782,84 @@ var Button = forwardRef(
795
782
  isDisabled = false,
796
783
  // Styling
797
784
  className,
798
- // Other props
785
+ // Other button props
799
786
  tabIndex = 0,
800
787
  type = "button",
801
- onPress,
788
+ // Passed through to ButtonHeadless → useButton
802
789
  ...props
803
790
  }, ref) => {
791
+ const buttonRef = useRef(null);
792
+ const resolvedRef = ref ?? buttonRef;
804
793
  const groupCtx = useOptionalButtonGroup();
805
794
  const isConnected = groupCtx?.variant === "connected";
806
- if (process.env.NODE_ENV === "development") {
807
- if (!children) {
808
- console.warn(
809
- "[Button] Button should have text content. Use IconButton for icon-only buttons."
810
- );
811
- }
812
- if (icon && trailingIcon) {
813
- console.warn("[Button] Button should have either icon or trailingIcon, not both.");
814
- }
815
- }
816
795
  const isButtonDisabled = isDisabled || loading;
796
+ const [isPressed, setIsPressed] = useState(false);
797
+ const handlePressStart = useCallback(() => setIsPressed(true), []);
798
+ const handlePressEnd = useCallback(() => setIsPressed(false), []);
799
+ const { isHovered, hoverProps } = useHover({ isDisabled: isButtonDisabled });
800
+ const { isFocusVisible, focusProps } = useFocusRing();
817
801
  const { onMouseDown: handleRipple, ripples } = useRipple({
818
802
  disabled: isButtonDisabled || disableRipple
819
803
  });
804
+ const buttonValue = props.value;
805
+ const isGroupSelected = isConnected && groupCtx && buttonValue ? groupCtx.selectedValues.has(buttonValue) : false;
820
806
  const connectedClasses = isConnected && groupCtx ? [
821
- ...getConnectedRadiusClasses(groupCtx, props?.value),
807
+ ...getConnectedRadiusClasses(groupCtx, buttonValue),
822
808
  groupCtx.enforceMinWidth ? "min-w-12" : ""
823
809
  ] : [];
810
+ const hasIcon = !!icon || !!trailingIcon;
811
+ if (process.env.NODE_ENV === "development") {
812
+ if (!children) {
813
+ console.warn(
814
+ "[Button] Button should have text content. Use IconButton for icon-only buttons."
815
+ );
816
+ }
817
+ }
824
818
  return /* @__PURE__ */ jsxs(
825
819
  ButtonHeadless,
826
820
  {
827
- ...props,
828
- ref,
821
+ ...mergeProps$1(
822
+ hoverProps,
823
+ focusProps,
824
+ // Track pressed state via useButton's press lifecycle callbacks,
825
+ // rather than a separate usePress hook, to avoid event handler conflicts.
826
+ { onPressStart: handlePressStart, onPressEnd: handlePressEnd },
827
+ props
828
+ ),
829
+ ref: resolvedRef,
829
830
  type,
830
831
  isDisabled: isButtonDisabled,
831
- ...onPress && { onPress },
832
832
  tabIndex,
833
833
  onMouseDown: handleRipple,
834
+ ...getInteractionDataAttributes({
835
+ isHovered,
836
+ isFocusVisible,
837
+ isPressed,
838
+ isDisabled: isButtonDisabled
839
+ }),
834
840
  "data-variant": variant,
835
- "data-color": color,
841
+ "data-with-icon": hasIcon ? "" : void 0,
842
+ "data-loading": loading ? "" : void 0,
843
+ "data-group-selected": isGroupSelected ? "" : void 0,
836
844
  className: cn(
837
- // Apply CVA variants (includes rounded-full base)
838
- buttonVariants({
839
- variant,
840
- color,
841
- size,
842
- fullWidth,
843
- disabled: isButtonDisabled,
844
- loading
845
- }),
845
+ buttonVariants({ variant, size, fullWidth }),
846
+ // group/button: enables group-data-[x]/button child selectors in all slots
847
+ // (added here, not in CVA, following the Switch pattern)
848
+ "group/button",
849
+ // Asymmetric border-radius easing: expressive when selected, decelerate when not
850
+ isGroupSelected ? "btn-transition-selected" : "",
846
851
  ...connectedClasses,
847
852
  // User custom classes
848
853
  className
849
854
  ),
850
855
  children: [
851
856
  ripples,
852
- icon && /* @__PURE__ */ jsx("span", { className: cn("relative z-10 inline-flex shrink-0", loading && "invisible"), children: icon }),
853
- loading && /* @__PURE__ */ jsx("span", { className: "relative z-10", children: /* @__PURE__ */ jsx(Spinner, {}) }),
854
- /* @__PURE__ */ jsx("span", { className: "relative z-10 inline-flex items-center", children }),
855
- trailingIcon && /* @__PURE__ */ jsx("span", { className: cn("relative z-10 inline-flex shrink-0", loading && "invisible"), children: trailingIcon })
857
+ /* @__PURE__ */ jsx("span", { className: cn(buttonStateLayerVariants({ variant })), "aria-hidden": "true" }),
858
+ /* @__PURE__ */ jsx("span", { className: cn(buttonFocusRingVariants()), "aria-hidden": "true" }),
859
+ icon && /* @__PURE__ */ jsx("span", { className: cn(buttonIconVariants({ hidden: loading })), children: icon }),
860
+ loading && /* @__PURE__ */ jsx(Spinner, {}),
861
+ /* @__PURE__ */ jsx("span", { className: cn(buttonLabelVariants()), children }),
862
+ trailingIcon && /* @__PURE__ */ jsx("span", { className: cn(buttonIconVariants({ hidden: loading })), children: trailingIcon })
856
863
  ]
857
864
  }
858
865
  );
@@ -866,6 +873,7 @@ var ButtonGroupHeadless = forwardRef(
866
873
  size = "medium",
867
874
  shape = "round",
868
875
  selectionMode,
876
+ isDisabled = false,
869
877
  // Selection — controlled
870
878
  selectedValues: controlledValues,
871
879
  onSelectionChange: onControlledChange,
@@ -887,7 +895,7 @@ var ButtonGroupHeadless = forwardRef(
887
895
  const isControlled = controlledValues !== void 0;
888
896
  const selectedValues = isControlled ? controlledValues : uncontrolledValues;
889
897
  const handleSelectionChange = (value) => {
890
- if (!selectionMode) return;
898
+ if (!selectionMode || isDisabled) return;
891
899
  let nextValues;
892
900
  if (selectionMode === "multi") {
893
901
  nextValues = new Set(selectedValues);
@@ -928,6 +936,7 @@ var ButtonGroupHeadless = forwardRef(
928
936
  selectionMode,
929
937
  selectedValues,
930
938
  onSelectionChange: handleSelectionChange,
939
+ isDisabled,
931
940
  connectedInnerRadius: getInnerRadius(size),
932
941
  connectedOuterRadius: getOuterRadius(shape, size),
933
942
  enforceMinWidth: variant === "connected" && (size === "extra-small" || size === "small")
@@ -940,9 +949,15 @@ var ButtonGroupHeadless = forwardRef(
940
949
  }
941
950
  );
942
951
  ButtonGroupHeadless.displayName = "ButtonGroupHeadless";
943
- var buttonGroupVariants = cva(
944
- // Base classes applied to every ButtonGroup container
945
- ["items-center"],
952
+ var buttonGroupRootVariants = cva(
953
+ [
954
+ // Layout
955
+ "items-center",
956
+ // Spatial motion for gap changes — standard spring (calm, utility UI)
957
+ "transition-[gap] duration-spring-standard-fast-spatial ease-spring-standard-fast-spatial",
958
+ // Disabled state — self-targeting data-[x]: selector on root
959
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-38"
960
+ ],
946
961
  {
947
962
  variants: {
948
963
  /**
@@ -990,6 +1005,14 @@ var buttonGroupVariants = cva(
990
1005
  }
991
1006
  }
992
1007
  );
1008
+ var buttonGroupFocusRingVariants = cva([
1009
+ "pointer-events-none absolute inset-[-3px] rounded-[inherit]",
1010
+ "outline outline-2 outline-offset-0 outline-secondary",
1011
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
1012
+ "opacity-0",
1013
+ "group-data-[focus-visible]/button-group:opacity-100"
1014
+ ]);
1015
+ var buttonGroupVariants = buttonGroupRootVariants;
993
1016
  var ButtonGroup = forwardRef(
994
1017
  ({
995
1018
  variant = "standard",
@@ -999,6 +1022,7 @@ var ButtonGroup = forwardRef(
999
1022
  selectedValues,
1000
1023
  onSelectionChange,
1001
1024
  defaultValue,
1025
+ isDisabled = false,
1002
1026
  children,
1003
1027
  className,
1004
1028
  ...htmlProps
@@ -1015,6 +1039,13 @@ var ButtonGroup = forwardRef(
1015
1039
  },
1016
1040
  [ref]
1017
1041
  );
1042
+ const hasSelection = useMemo(() => {
1043
+ if (selectedValues) return selectedValues.size > 0;
1044
+ if (defaultValue) {
1045
+ return Array.isArray(defaultValue) ? defaultValue.length > 0 : true;
1046
+ }
1047
+ return false;
1048
+ }, [selectedValues, defaultValue]);
1018
1049
  if (process.env.NODE_ENV === "development") {
1019
1050
  const childArray = Array.isArray(children) ? children : [children];
1020
1051
  for (const child of childArray) {
@@ -1063,7 +1094,12 @@ var ButtonGroup = forwardRef(
1063
1094
  selectedValues,
1064
1095
  onSelectionChange,
1065
1096
  defaultValue,
1066
- className: cn(buttonGroupVariants({ variant, size }), className),
1097
+ isDisabled,
1098
+ className: cn(buttonGroupRootVariants({ variant, size }), "group/button-group", className),
1099
+ ...getInteractionDataAttributes({ isDisabled }),
1100
+ "data-connected": variant === "connected" ? "" : void 0,
1101
+ "data-has-selection": hasSelection ? "" : void 0,
1102
+ "data-selection-mode": selectionMode ?? void 0,
1067
1103
  children
1068
1104
  }
1069
1105
  );
@@ -1077,79 +1113,113 @@ var IconButtonHeadless = forwardRef(
1077
1113
  tabIndex = 0,
1078
1114
  onMouseDown,
1079
1115
  type,
1080
- selected,
1116
+ isSelected,
1117
+ isToggle = false,
1118
+ isDisabled = false,
1081
1119
  "aria-label": ariaLabel,
1082
1120
  title,
1083
1121
  ...props
1084
1122
  }, forwardedRef) => {
1085
1123
  const internalRef = useRef(null);
1086
1124
  const ref = forwardedRef ?? internalRef;
1087
- const { buttonProps } = useButton(
1125
+ const { buttonProps, isPressed } = useButton(
1088
1126
  {
1089
1127
  ...props,
1090
- // Ensure element type is 'button' for proper semantics
1091
1128
  elementType: "button",
1092
- // Pass aria-label
1093
- "aria-label": ariaLabel
1129
+ "aria-label": ariaLabel,
1130
+ isDisabled
1094
1131
  },
1095
1132
  ref
1096
1133
  );
1134
+ const { isHovered, hoverProps } = useHover({ isDisabled });
1135
+ const { isFocusVisible, focusProps } = useFocusRing();
1097
1136
  const domProps = filterDOMProps(props);
1098
- const mergedProps = mergeProps(
1099
- buttonProps,
1100
- domProps,
1137
+ const mergedProps = mergeProps(buttonProps, hoverProps, focusProps, domProps, {
1138
+ tabIndex,
1139
+ className,
1140
+ onMouseDown,
1141
+ type: type ?? "button",
1142
+ ...title && { title },
1143
+ // aria-pressed only when acting as a toggle button
1144
+ ...isToggle && { "aria-pressed": isSelected ?? false }
1145
+ });
1146
+ return /* @__PURE__ */ jsx(
1147
+ "button",
1101
1148
  {
1102
- tabIndex,
1103
- className,
1104
- onMouseDown,
1105
- type: type ?? "button",
1106
- // Add aria-pressed for toggle buttons (only if selected is defined)
1107
- ...selected !== void 0 && { "aria-pressed": selected },
1108
- // Add title if provided
1109
- ...title && { title }
1149
+ ...mergedProps,
1150
+ ref,
1151
+ type: type === "submit" ? "submit" : type === "reset" ? "reset" : "button",
1152
+ ...getInteractionDataAttributes({
1153
+ isHovered,
1154
+ isFocusVisible,
1155
+ isPressed,
1156
+ ...isToggle ? { isSelected: isSelected ?? false } : {},
1157
+ isDisabled
1158
+ }),
1159
+ "data-toggle": isToggle ? "" : void 0,
1160
+ children
1110
1161
  }
1111
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1112
- );
1113
- return (
1114
- // eslint-disable-next-line react/button-has-type
1115
- /* @__PURE__ */ jsx("button", { ...mergedProps, ref, type: type ?? "button", children })
1116
1162
  );
1117
1163
  }
1118
1164
  );
1119
1165
  IconButtonHeadless.displayName = "IconButtonHeadless";
1120
- var iconButtonVariants = cva(
1166
+ var iconButtonRootVariants = cva(
1121
1167
  [
1122
- // Base classes (always applied)
1123
- "relative inline-flex items-center justify-center cursor-pointer",
1124
- "overflow-hidden rounded-full",
1125
- // Circular shape
1126
- // Spatial (border-radius, transform): expressive fast spring350ms, visible overshoot
1127
- "transition-all duration-expressive-fast-spatial ease-expressive-fast-spatial",
1128
- "focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2",
1129
- // State layers — effects token: opacity only, no overshoot
1130
- "before:absolute before:inset-0 before:rounded-[inherit]",
1131
- "before:transition-opacity before:duration-spring-standard-fast-effects before:ease-spring-standard-fast-effects",
1132
- "before:bg-current before:opacity-0",
1133
- "hover:before:opacity-8",
1134
- "focus-visible:before:opacity-12",
1135
- "active:before:opacity-12"
1168
+ // Layout
1169
+ "relative inline-flex items-center justify-center",
1170
+ "cursor-pointer select-none",
1171
+ "overflow-hidden",
1172
+ // Corner radius driven by CSS variableset per shape×size in compoundVariants.
1173
+ // Fallback 9999px is only reached if both shape and size props are absent,
1174
+ // which cannot happen in normal usage.
1175
+ "rounded-[var(--ib-radius,9999px)]",
1176
+ // Split MD3 transition via the existing btn-transition utility:
1177
+ // border-radius → emphasized-decelerate (no overshoot, no sharp-corner flash)
1178
+ // color/bg/border/opacity → standard-fast-effects (no overshoot on effects)
1179
+ // This is identical to the approach used by Button/connected ButtonGroup and is
1180
+ // the standard fix for the 9999px overshoot problem documented in styles.css.
1181
+ "btn-transition",
1182
+ // Background + border + text driven from CSS role variables
1183
+ "bg-[var(--ib-bg,transparent)]",
1184
+ "border border-[var(--ib-border,transparent)]",
1185
+ "text-[var(--ib-fg,currentColor)]",
1186
+ // Toggle: off state (data-toggle present but data-selected absent)
1187
+ // Uses doubly-chained selector to beat single-chain specificity of defaults
1188
+ "data-[toggle]:bg-[var(--ib-bg-off,var(--ib-bg,transparent))]",
1189
+ "data-[toggle]:text-[var(--ib-fg-off,var(--ib-fg,currentColor))]",
1190
+ // Selected state
1191
+ "data-[selected]:bg-[var(--ib-bg-on,var(--ib-bg,transparent))]",
1192
+ "data-[selected]:text-[var(--ib-fg-on,var(--ib-fg,currentColor))]",
1193
+ "data-[selected]:border-transparent",
1194
+ // Press shape-morph: radius collapses to --ib-radius-press on press
1195
+ // (only has visual effect when --ib-radius-press differs from --ib-radius)
1196
+ "data-[pressed]:rounded-[var(--ib-radius-press,var(--ib-radius,9999px))]",
1197
+ // Focus ring (outline, not a state layer — stays outside overflow-hidden
1198
+ // because it's drawn as outline on the root element itself)
1199
+ "outline-none",
1200
+ "group-data-[focus-visible]/icon-button:outline-2",
1201
+ "group-data-[focus-visible]/icon-button:outline-offset-2",
1202
+ "group-data-[focus-visible]/icon-button:outline-secondary",
1203
+ // Disabled — content opacity 38%, container handled per variant via CSS vars
1204
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none",
1205
+ "data-[disabled]:text-on-surface/38"
1206
+ // Filled/tonal/outlined-selected backgrounds collapse to on-surface/12 — set
1207
+ // via compoundVariants on the root for variants that have a container.
1208
+ // For variants with transparent bg (standard, outlined-unselected) we do nothing.
1136
1209
  ],
1137
1210
  {
1138
1211
  variants: {
1139
1212
  /**
1140
- * Button variant (MD3 specification)
1213
+ * Visual style variant (MD3 icon button types)
1141
1214
  */
1142
1215
  variant: {
1143
- standard: "bg-transparent",
1144
- // No background
1145
- filled: "shadow-none",
1146
- // Solid background
1147
- tonal: "",
1148
- // Container background
1149
- outlined: "bg-transparent border border-outline"
1216
+ standard: "",
1217
+ filled: "data-[disabled]:bg-on-surface/12",
1218
+ tonal: "data-[disabled]:bg-on-surface/12",
1219
+ outlined: ""
1150
1220
  },
1151
1221
  /**
1152
- * Color scheme (MD3 color roles)
1222
+ * Color scheme sets CSS role variables via compoundVariants.
1153
1223
  */
1154
1224
  color: {
1155
1225
  primary: "",
@@ -1158,180 +1228,400 @@ var iconButtonVariants = cva(
1158
1228
  error: ""
1159
1229
  },
1160
1230
  /**
1161
- * Button size (square dimensions)
1231
+ * Size tier (M3 Expressive 5-tier)
1162
1232
  */
1163
1233
  size: {
1164
- small: "h-8 w-8",
1165
- // 32×32px
1166
- medium: "h-10 w-10",
1167
- // 40×40px (default)
1168
- large: "h-12 w-12"
1169
- // 48×48px
1234
+ xsmall: "h-8",
1235
+ small: "h-10",
1236
+ medium: "h-14",
1237
+ large: "h-24",
1238
+ xlarge: "h-[8.5rem]"
1170
1239
  },
1171
1240
  /**
1172
- * Selected state (for toggle buttons)
1241
+ * Width variant adjusts container width
1173
1242
  */
1174
- selected: {
1175
- true: "",
1176
- false: ""
1243
+ width: {
1244
+ narrow: "",
1245
+ default: "",
1246
+ wide: ""
1177
1247
  },
1178
1248
  /**
1179
- * Disabled state
1249
+ * Shape — base values only; per-size radii set via compoundVariants below.
1250
+ *
1251
+ * round: --ib-radius = half the container height (true circle), set per size.
1252
+ * --ib-radius-press = square corner for that size (set per size).
1253
+ * Morph distance is small (e.g. 28px → 16px for medium), so the
1254
+ * emphasized-decelerate curve from btn-transition produces a smooth,
1255
+ * non-overshooting transition. The old 9999px fallback caused the
1256
+ * spring to overshoot below 0 = sharp-corner flash.
1257
+ * square: --ib-radius = size-tiered MD3 corner, set per size. No press morph.
1180
1258
  */
1181
- isDisabled: {
1182
- true: "pointer-events-none cursor-not-allowed opacity-38",
1183
- false: ""
1259
+ shape: {
1260
+ round: [],
1261
+ square: []
1184
1262
  }
1185
1263
  },
1186
- /**
1187
- * Compound variants - combinations of variant + color + selected
1188
- */
1189
1264
  compoundVariants: [
1190
- // ====================
1191
- // STANDARD VARIANTS
1192
- // ====================
1193
- {
1194
- variant: "standard",
1195
- selected: false,
1196
- className: "text-on-surface-variant"
1197
- },
1265
+ // ══════════════════════════════════════════════════════════════════════
1266
+ // SIZE × WIDTH — container width
1267
+ // ══════════════════════════════════════════════════════════════════════
1268
+ { size: "xsmall", width: "narrow", className: "w-6" },
1269
+ { size: "xsmall", width: "default", className: "w-8" },
1270
+ { size: "xsmall", width: "wide", className: "w-10" },
1271
+ { size: "small", width: "narrow", className: "w-8" },
1272
+ { size: "small", width: "default", className: "w-10" },
1273
+ { size: "small", width: "wide", className: "w-13" },
1274
+ { size: "medium", width: "narrow", className: "w-12" },
1275
+ { size: "medium", width: "default", className: "w-14" },
1276
+ { size: "medium", width: "wide", className: "w-18" },
1277
+ { size: "large", width: "narrow", className: "w-18" },
1278
+ { size: "large", width: "default", className: "w-24" },
1279
+ { size: "large", width: "wide", className: "w-32" },
1280
+ { size: "xlarge", width: "narrow", className: "w-24" },
1281
+ { size: "xlarge", width: "default", className: "w-[8.5rem]" },
1282
+ { size: "xlarge", width: "wide", className: "w-42" },
1283
+ // ══════════════════════════════════════════════════════════════════════
1284
+ // SHAPE × SIZE — corner radii for both round and square shapes
1285
+ // ══════════════════════════════════════════════════════════════════════
1286
+ //
1287
+ // Round rest radius = half container height (true circle).
1288
+ // Using the exact half-height keeps the morph distance small, so the
1289
+ // no-overshoot emphasized-decelerate curve in btn-transition produces a
1290
+ // smooth animation. Using 9999px was the original cause of the sharp-
1291
+ // corner flash (the spring overshoots below 0 before settling).
1292
+ //
1293
+ // xsmall h-8 = 32px → half = 16px = 1rem
1294
+ // small h-10 = 40px → half = 20px = 1.25rem
1295
+ // medium h-14 = 56px → half = 28px = 1.75rem
1296
+ // large h-24 = 96px → half = 48px = 3rem
1297
+ // xlarge h-34 = 136px → half = 68px = 4.25rem
1298
+ //
1299
+ // Round press-morph target = MD3 square corner for that size tier.
1300
+ // Square rest radius = same MD3 corner (no morph).
1301
+ // ── round: rest radius (half height) ──────────────────────────────────
1302
+ { shape: "round", size: "xsmall", className: "[--ib-radius:1rem]" },
1303
+ { shape: "round", size: "small", className: "[--ib-radius:1.25rem]" },
1304
+ { shape: "round", size: "medium", className: "[--ib-radius:1.75rem]" },
1305
+ { shape: "round", size: "large", className: "[--ib-radius:3rem]" },
1306
+ { shape: "round", size: "xlarge", className: "[--ib-radius:4.25rem]" },
1307
+ // ── round: press-morph target (square corner for that size) ───────────
1308
+ { shape: "round", size: "xsmall", className: "[--ib-radius-press:0.75rem]" },
1309
+ { shape: "round", size: "small", className: "[--ib-radius-press:0.75rem]" },
1310
+ { shape: "round", size: "medium", className: "[--ib-radius-press:1rem]" },
1311
+ { shape: "round", size: "large", className: "[--ib-radius-press:1.75rem]" },
1312
+ { shape: "round", size: "xlarge", className: "[--ib-radius-press:1.75rem]" },
1313
+ // ── square: rest radius (MD3 shape scale) ─────────────────────────────
1314
+ // xsmall / small → 12px (0.75rem), medium → 16px (1rem), large / xlarge → 28px (1.75rem)
1315
+ { shape: "square", size: "xsmall", className: "[--ib-radius:0.75rem]" },
1316
+ { shape: "square", size: "small", className: "[--ib-radius:0.75rem]" },
1317
+ { shape: "square", size: "medium", className: "[--ib-radius:1rem]" },
1318
+ { shape: "square", size: "large", className: "[--ib-radius:1.75rem]" },
1319
+ { shape: "square", size: "xlarge", className: "[--ib-radius:1.75rem]" },
1320
+ // ══════════════════════════════════════════════════════════════════════
1321
+ // VARIANT × COLOR — CSS role variable assignments
1322
+ // Only variant × color (design-time decisions); no state variants here.
1323
+ // ══════════════════════════════════════════════════════════════════════
1324
+ // ── STANDARD ──────────────────────────────────────────────────────────
1325
+ // Non-toggle standard: transparent bg, on-surface-variant fg
1326
+ // Selected: primary fg
1327
+ // State layer: on-surface-variant (unselected) / primary (selected)
1198
1328
  {
1199
1329
  variant: "standard",
1200
- selected: true,
1201
- className: "text-primary"
1202
- },
1203
- // ====================
1204
- // FILLED VARIANTS (UNSELECTED)
1205
- // ====================
1206
- {
1207
- variant: "filled",
1208
1330
  color: "primary",
1209
- selected: false,
1210
- className: "bg-primary text-on-primary"
1331
+ className: [
1332
+ "[--ib-bg:transparent]",
1333
+ "[--ib-fg:var(--color-on-surface-variant)]",
1334
+ "[--ib-fg-on:var(--color-primary)]",
1335
+ "[--ib-sl:var(--color-on-surface-variant)]",
1336
+ // toggle-off same as non-toggle
1337
+ "[--ib-bg-off:transparent]",
1338
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1339
+ // toggle-on: selected
1340
+ "[--ib-bg-on:transparent]"
1341
+ ]
1211
1342
  },
1212
1343
  {
1213
- variant: "filled",
1344
+ variant: "standard",
1214
1345
  color: "secondary",
1215
- selected: false,
1216
- className: "bg-secondary text-on-secondary"
1346
+ className: [
1347
+ "[--ib-bg:transparent]",
1348
+ "[--ib-fg:var(--color-on-surface-variant)]",
1349
+ "[--ib-fg-on:var(--color-secondary)]",
1350
+ "[--ib-sl:var(--color-on-surface-variant)]",
1351
+ "[--ib-bg-off:transparent]",
1352
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1353
+ "[--ib-bg-on:transparent]"
1354
+ ]
1217
1355
  },
1218
1356
  {
1219
- variant: "filled",
1357
+ variant: "standard",
1220
1358
  color: "tertiary",
1221
- selected: false,
1222
- className: "bg-tertiary text-on-tertiary"
1359
+ className: [
1360
+ "[--ib-bg:transparent]",
1361
+ "[--ib-fg:var(--color-on-surface-variant)]",
1362
+ "[--ib-fg-on:var(--color-tertiary)]",
1363
+ "[--ib-sl:var(--color-on-surface-variant)]",
1364
+ "[--ib-bg-off:transparent]",
1365
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1366
+ "[--ib-bg-on:transparent]"
1367
+ ]
1223
1368
  },
1224
1369
  {
1225
- variant: "filled",
1370
+ variant: "standard",
1226
1371
  color: "error",
1227
- selected: false,
1228
- className: "bg-error text-on-error"
1372
+ className: [
1373
+ "[--ib-bg:transparent]",
1374
+ "[--ib-fg:var(--color-on-surface-variant)]",
1375
+ "[--ib-fg-on:var(--color-error)]",
1376
+ "[--ib-sl:var(--color-on-surface-variant)]",
1377
+ "[--ib-bg-off:transparent]",
1378
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1379
+ "[--ib-bg-on:transparent]"
1380
+ ]
1229
1381
  },
1230
- // ====================
1231
- // FILLED VARIANTS (SELECTED - uses container colors)
1232
- // ====================
1382
+ // ── FILLED ────────────────────────────────────────────────────────────
1383
+ // Non-toggle: bg primary / fg on-primary
1384
+ // Toggle off: bg surface-container-highest / fg primary
1385
+ // Toggle on (selected): bg primary / fg on-primary
1386
+ // State layer: on-primary (non-toggle / selected), primary (toggle-off)
1233
1387
  {
1234
1388
  variant: "filled",
1235
1389
  color: "primary",
1236
- selected: true,
1237
- className: "bg-primary-container text-on-primary-container"
1390
+ className: [
1391
+ "[--ib-bg:var(--color-primary)]",
1392
+ "[--ib-fg:var(--color-on-primary)]",
1393
+ "[--ib-sl:var(--color-on-primary)]",
1394
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1395
+ "[--ib-fg-off:var(--color-primary)]",
1396
+ "[--ib-bg-on:var(--color-primary)]",
1397
+ "[--ib-fg-on:var(--color-on-primary)]"
1398
+ ]
1238
1399
  },
1239
1400
  {
1240
1401
  variant: "filled",
1241
1402
  color: "secondary",
1242
- selected: true,
1243
- className: "bg-secondary-container text-on-secondary-container"
1403
+ className: [
1404
+ "[--ib-bg:var(--color-secondary)]",
1405
+ "[--ib-fg:var(--color-on-secondary)]",
1406
+ "[--ib-sl:var(--color-on-secondary)]",
1407
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1408
+ "[--ib-fg-off:var(--color-secondary)]",
1409
+ "[--ib-bg-on:var(--color-secondary)]",
1410
+ "[--ib-fg-on:var(--color-on-secondary)]"
1411
+ ]
1244
1412
  },
1245
1413
  {
1246
1414
  variant: "filled",
1247
1415
  color: "tertiary",
1248
- selected: true,
1249
- className: "bg-tertiary-container text-on-tertiary-container"
1416
+ className: [
1417
+ "[--ib-bg:var(--color-tertiary)]",
1418
+ "[--ib-fg:var(--color-on-tertiary)]",
1419
+ "[--ib-sl:var(--color-on-tertiary)]",
1420
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1421
+ "[--ib-fg-off:var(--color-tertiary)]",
1422
+ "[--ib-bg-on:var(--color-tertiary)]",
1423
+ "[--ib-fg-on:var(--color-on-tertiary)]"
1424
+ ]
1250
1425
  },
1251
1426
  {
1252
1427
  variant: "filled",
1253
1428
  color: "error",
1254
- selected: true,
1255
- className: "bg-error-container text-on-error-container"
1429
+ className: [
1430
+ "[--ib-bg:var(--color-error)]",
1431
+ "[--ib-fg:var(--color-on-error)]",
1432
+ "[--ib-sl:var(--color-on-error)]",
1433
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1434
+ "[--ib-fg-off:var(--color-error)]",
1435
+ "[--ib-bg-on:var(--color-error)]",
1436
+ "[--ib-fg-on:var(--color-on-error)]"
1437
+ ]
1256
1438
  },
1257
- // ====================
1258
- // TONAL VARIANTS (UNSELECTED)
1259
- // ====================
1439
+ // ── TONAL ─────────────────────────────────────────────────────────────
1440
+ // Non-toggle: bg secondary-container / fg on-secondary-container
1441
+ // Toggle off: bg surface-container-highest / fg on-surface-variant
1442
+ // Toggle on (selected): bg secondary-container / fg on-secondary-container
1260
1443
  {
1261
1444
  variant: "tonal",
1262
1445
  color: "primary",
1263
- selected: false,
1264
- className: "bg-secondary-container text-on-secondary-container"
1446
+ className: [
1447
+ "[--ib-bg:var(--color-secondary-container)]",
1448
+ "[--ib-fg:var(--color-on-secondary-container)]",
1449
+ "[--ib-sl:var(--color-on-secondary-container)]",
1450
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1451
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1452
+ "[--ib-bg-on:var(--color-secondary-container)]",
1453
+ "[--ib-fg-on:var(--color-on-secondary-container)]"
1454
+ ]
1265
1455
  },
1266
1456
  {
1267
1457
  variant: "tonal",
1268
1458
  color: "secondary",
1269
- selected: false,
1270
- className: "bg-secondary-container text-on-secondary-container"
1459
+ className: [
1460
+ "[--ib-bg:var(--color-secondary-container)]",
1461
+ "[--ib-fg:var(--color-on-secondary-container)]",
1462
+ "[--ib-sl:var(--color-on-secondary-container)]",
1463
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1464
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1465
+ "[--ib-bg-on:var(--color-secondary-container)]",
1466
+ "[--ib-fg-on:var(--color-on-secondary-container)]"
1467
+ ]
1271
1468
  },
1272
1469
  {
1273
1470
  variant: "tonal",
1274
1471
  color: "tertiary",
1275
- selected: false,
1276
- className: "bg-tertiary-container text-on-tertiary-container"
1472
+ className: [
1473
+ "[--ib-bg:var(--color-tertiary-container)]",
1474
+ "[--ib-fg:var(--color-on-tertiary-container)]",
1475
+ "[--ib-sl:var(--color-on-tertiary-container)]",
1476
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1477
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1478
+ "[--ib-bg-on:var(--color-tertiary-container)]",
1479
+ "[--ib-fg-on:var(--color-on-tertiary-container)]"
1480
+ ]
1277
1481
  },
1278
1482
  {
1279
1483
  variant: "tonal",
1280
1484
  color: "error",
1281
- selected: false,
1282
- className: "bg-error-container text-on-error-container"
1485
+ className: [
1486
+ "[--ib-bg:var(--color-error-container)]",
1487
+ "[--ib-fg:var(--color-on-error-container)]",
1488
+ "[--ib-sl:var(--color-on-error-container)]",
1489
+ "[--ib-bg-off:var(--color-surface-container-highest)]",
1490
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1491
+ "[--ib-bg-on:var(--color-error-container)]",
1492
+ "[--ib-fg-on:var(--color-on-error-container)]"
1493
+ ]
1283
1494
  },
1284
- // ====================
1285
- // TONAL VARIANTS (SELECTED - uses tertiary container)
1286
- // ====================
1495
+ // ── OUTLINED ──────────────────────────────────────────────────────────
1496
+ // Non-toggle: transparent bg, border-outline, on-surface-variant fg
1497
+ // Toggle off: same as non-toggle
1498
+ // Toggle on (selected): inverse-surface bg, inverse-on-surface fg, no border
1499
+ // Disabled: border becomes on-surface/12 (set via Tailwind utility on root)
1287
1500
  {
1288
- variant: "tonal",
1289
- selected: true,
1290
- className: "bg-tertiary-container text-on-tertiary-container"
1501
+ variant: "outlined",
1502
+ color: "primary",
1503
+ className: [
1504
+ "[--ib-bg:transparent]",
1505
+ "[--ib-fg:var(--color-on-surface-variant)]",
1506
+ "[--ib-sl:var(--color-on-surface-variant)]",
1507
+ "[--ib-border:var(--color-outline)]",
1508
+ "[--ib-bg-off:transparent]",
1509
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1510
+ "[--ib-bg-on:var(--color-inverse-surface)]",
1511
+ "[--ib-fg-on:var(--color-inverse-on-surface)]",
1512
+ // Disabled outlined border
1513
+ "data-[disabled]:border-on-surface/12"
1514
+ ]
1291
1515
  },
1292
- // ====================
1293
- // OUTLINED VARIANTS (UNSELECTED)
1294
- // ====================
1295
1516
  {
1296
1517
  variant: "outlined",
1297
- selected: false,
1298
- className: "text-on-surface-variant"
1518
+ color: "secondary",
1519
+ className: [
1520
+ "[--ib-bg:transparent]",
1521
+ "[--ib-fg:var(--color-on-surface-variant)]",
1522
+ "[--ib-sl:var(--color-on-surface-variant)]",
1523
+ "[--ib-border:var(--color-outline)]",
1524
+ "[--ib-bg-off:transparent]",
1525
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1526
+ "[--ib-bg-on:var(--color-inverse-surface)]",
1527
+ "[--ib-fg-on:var(--color-inverse-on-surface)]",
1528
+ "data-[disabled]:border-on-surface/12"
1529
+ ]
1299
1530
  },
1300
- // ====================
1301
- // OUTLINED VARIANTS (SELECTED - uses inverse colors)
1302
- // ====================
1303
1531
  {
1304
1532
  variant: "outlined",
1305
- selected: true,
1306
- className: "bg-inverse-surface text-inverse-on-surface border-transparent"
1533
+ color: "tertiary",
1534
+ className: [
1535
+ "[--ib-bg:transparent]",
1536
+ "[--ib-fg:var(--color-on-surface-variant)]",
1537
+ "[--ib-sl:var(--color-on-surface-variant)]",
1538
+ "[--ib-border:var(--color-outline)]",
1539
+ "[--ib-bg-off:transparent]",
1540
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1541
+ "[--ib-bg-on:var(--color-inverse-surface)]",
1542
+ "[--ib-fg-on:var(--color-inverse-on-surface)]",
1543
+ "data-[disabled]:border-on-surface/12"
1544
+ ]
1545
+ },
1546
+ {
1547
+ variant: "outlined",
1548
+ color: "error",
1549
+ className: [
1550
+ "[--ib-bg:transparent]",
1551
+ "[--ib-fg:var(--color-on-surface-variant)]",
1552
+ "[--ib-sl:var(--color-on-surface-variant)]",
1553
+ "[--ib-border:var(--color-outline)]",
1554
+ "[--ib-bg-off:transparent]",
1555
+ "[--ib-fg-off:var(--color-on-surface-variant)]",
1556
+ "[--ib-bg-on:var(--color-inverse-surface)]",
1557
+ "[--ib-fg-on:var(--color-inverse-on-surface)]",
1558
+ "data-[disabled]:border-on-surface/12"
1559
+ ]
1307
1560
  }
1308
1561
  ],
1309
- /**
1310
- * Default variants
1311
- */
1312
1562
  defaultVariants: {
1313
1563
  variant: "standard",
1314
1564
  color: "primary",
1315
1565
  size: "medium",
1316
- selected: false,
1317
- isDisabled: false
1566
+ width: "default",
1567
+ shape: "round"
1568
+ }
1569
+ }
1570
+ );
1571
+ var iconButtonStateLayerVariants = cva([
1572
+ "absolute inset-0 rounded-[inherit] pointer-events-none opacity-0",
1573
+ "bg-[var(--ib-sl,currentColor)]",
1574
+ // Effects transition (opacity — no spatial overshoot)
1575
+ "transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
1576
+ // Interaction opacities (MD3: hover 8%, focus/pressed 10%)
1577
+ "group-data-[hovered]/icon-button:opacity-8",
1578
+ "group-data-[focus-visible]/icon-button:opacity-10",
1579
+ "group-data-[pressed]/icon-button:opacity-10",
1580
+ // No state layer when disabled
1581
+ "group-data-[disabled]/icon-button:hidden"
1582
+ ]);
1583
+ var iconButtonIconVariants = cva(
1584
+ [
1585
+ "relative z-10 inline-flex shrink-0 items-center justify-center",
1586
+ "transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
1587
+ ],
1588
+ {
1589
+ variants: {
1590
+ size: {
1591
+ xsmall: "size-5",
1592
+ // 20dp
1593
+ small: "size-6",
1594
+ // 24dp
1595
+ medium: "size-6",
1596
+ // 24dp
1597
+ large: "size-8",
1598
+ // 32dp
1599
+ xlarge: "size-10"
1600
+ // 40dp
1601
+ }
1602
+ },
1603
+ defaultVariants: {
1604
+ size: "medium"
1318
1605
  }
1319
1606
  }
1320
1607
  );
1321
1608
  var IconButton = forwardRef(
1322
1609
  ({
1323
- // Variant props (CVA)
1610
+ // Variant props (CVA / design-time)
1324
1611
  variant = "standard",
1325
1612
  color = "primary",
1326
1613
  size = "medium",
1614
+ width = "default",
1615
+ shape = "round",
1327
1616
  // IconButton specific props
1328
1617
  children,
1618
+ selectedIcon,
1329
1619
  value,
1330
1620
  selected,
1331
1621
  disableRipple = false,
1332
1622
  className,
1333
1623
  // React Aria props
1334
- isDisabled: propIsDisabled = false,
1624
+ isDisabled = false,
1335
1625
  onPress,
1336
1626
  onMouseDown,
1337
1627
  "aria-label": ariaLabel,
@@ -1350,7 +1640,8 @@ var IconButton = forwardRef(
1350
1640
  console.warn("[IconButton] IconButton should have an icon as children.");
1351
1641
  }
1352
1642
  }
1353
- const isDisabled = propIsDisabled;
1643
+ const isToggle = selected !== void 0;
1644
+ const isSelected = isToggle ? selected ?? false : false;
1354
1645
  const { onMouseDown: handleRipple, ripples } = useRipple({
1355
1646
  disabled: isDisabled || disableRipple
1356
1647
  });
@@ -1363,44 +1654,42 @@ var IconButton = forwardRef(
1363
1654
  onMouseDown: mergedOnMouseDown,
1364
1655
  isDisabled
1365
1656
  });
1657
+ const isGroupSelected = isConnected && groupCtx && value ? groupCtx.selectedValues.has(value) : false;
1366
1658
  const connectedClasses = isConnected && groupCtx ? [
1367
1659
  ...getConnectedRadiusClasses(groupCtx, value),
1368
1660
  groupCtx.enforceMinWidth ? "min-w-12" : ""
1369
1661
  ] : [];
1662
+ const iconNode = isToggle && isSelected && selectedIcon ? selectedIcon : children;
1370
1663
  return /* @__PURE__ */ jsxs(
1371
1664
  IconButtonHeadless,
1372
1665
  {
1373
1666
  ref,
1374
1667
  className: cn(
1375
- // Base classes
1376
- "relative inline-flex items-center justify-center",
1377
- "overflow-hidden rounded-full",
1378
- // Circular shape (overridden by connected group classes)
1379
- // Spatial (border-radius, transform): expressive fast spring — 350ms, visible overshoot
1380
- "duration-expressive-fast-spatial ease-expressive-fast-spatial transition-all",
1381
- "focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2",
1382
- // State layers (hover, focus, active) — effects token: opacity, no overshoot
1383
- "before:absolute before:inset-0 before:rounded-[inherit]",
1384
- "before:duration-spring-standard-fast-effects before:ease-spring-standard-fast-effects before:transition-opacity",
1385
- "before:bg-current before:opacity-0",
1386
- "hover:before:opacity-8",
1387
- "focus-visible:before:opacity-12",
1388
- "active:before:opacity-12",
1389
- // CVA variants
1390
- iconButtonVariants({ variant, color, size, selected: selected ?? false, isDisabled }),
1668
+ // Root CVA — sets CSS role variables, dimensions, shape, transitions
1669
+ iconButtonRootVariants({ variant, color, size, width, shape }),
1670
+ // Group scope for child slot selectors
1671
+ "group/icon-button",
1672
+ // ButtonGroup asymmetric border-radius easing (connected selection morph)
1673
+ isGroupSelected ? "btn-transition-selected" : "",
1391
1674
  ...connectedClasses,
1392
- // User custom classes
1675
+ // Consumer custom classes
1393
1676
  className
1394
1677
  ),
1395
1678
  "aria-label": ariaLabel,
1679
+ isSelected,
1680
+ isToggle,
1396
1681
  "data-variant": variant,
1397
1682
  "data-color": color,
1398
- ...selected !== void 0 && { selected },
1683
+ "data-size": size,
1684
+ "data-width": width,
1685
+ "data-shape": shape,
1686
+ "data-group-selected": isGroupSelected ? "" : void 0,
1399
1687
  ...title && { title },
1400
1688
  ...mergedPropsValue,
1401
1689
  children: [
1690
+ /* @__PURE__ */ jsx("span", { className: iconButtonStateLayerVariants(), "aria-hidden": "true", "data-state-layer": "" }),
1402
1691
  ripples,
1403
- /* @__PURE__ */ jsx("span", { className: "relative z-10 inline-flex shrink-0", children })
1692
+ /* @__PURE__ */ jsx("span", { className: iconButtonIconVariants({ size }), "data-icon-slot": "", "aria-hidden": "true", children: iconNode })
1404
1693
  ]
1405
1694
  }
1406
1695
  );
@@ -4786,20 +5075,6 @@ var BadgeContent = forwardRef(
4786
5075
  }
4787
5076
  );
4788
5077
  BadgeContent.displayName = "BadgeContent";
4789
- var QUERY = "(prefers-reduced-motion: reduce)";
4790
- function useReducedMotion() {
4791
- const [reduced, setReduced] = useState(() => {
4792
- if (typeof window === "undefined") return false;
4793
- return window.matchMedia(QUERY).matches;
4794
- });
4795
- useEffect(() => {
4796
- const mql = window.matchMedia(QUERY);
4797
- const handler = (e) => setReduced(e.matches);
4798
- mql.addEventListener("change", handler);
4799
- return () => mql.removeEventListener("change", handler);
4800
- }, []);
4801
- return reduced;
4802
- }
4803
5078
  var Badge = forwardRef(
4804
5079
  ({
4805
5080
  count,
@@ -14792,6 +15067,6 @@ var DateField = forwardRef((props, forwardedRef) => {
14792
15067
  });
14793
15068
  DateField.displayName = "DateField";
14794
15069
 
14795
- export { AppBar, AppBarHeadless, Badge, BadgeContent, BadgeHeadless, BottomSheet, BottomSheetContext, BottomSheetHandle, BottomSheetHeadless, Button, ButtonGroup, ButtonGroupContext, ButtonGroupHeadless, CalendarCore, Card, CardActions, CardContent, CardHeader, CardHeadless, CardMedia, Checkbox, Chip, ChipHeadless, ChipSet, DateField, DatePicker, DatePickerDocked, DatePickerModal, DatePickerModalInput, Dialog, DialogActions, DialogContent, DialogContext, DialogHeadless, DialogHeadline, Divider, DividerHeadless, Drawer, DrawerIconOnlyContext, DrawerItem, DrawerSection, FAB, FABHeadless, FABMenu, FABMenuContext, FABMenuHeadless, FABMenuItem, HeadlessDrawer, HeadlessDrawerItem, HeadlessMenu, HeadlessMenuDivider, HeadlessMenuItem, HeadlessMenuSection, HeadlessMenuTrigger, HeadlessNavigationBar, HeadlessNavigationBarItem, HeadlessTab, HeadlessTabList, HeadlessTabPanel, IconButton, IconButtonHeadless, List, ListHeadless, ListItem, ListItemHeadless, ListItemLeading, ListItemText, ListItemTrailing, Menu, MenuContext, MenuDivider, MenuItem, MenuSection, MenuTrigger, NavigationBar, NavigationBarItem, Progress, ProgressHeadless, Radio, RadioGroup, RadioGroupHeadless, RadioHeadless, RichTooltip, STATE_LAYER_OPACITY, Search, SearchBar, SearchBarHeadless, SearchView, SearchViewHeadless, Slider, SliderHeadless, Snackbar, SnackbarContext, SnackbarHeadless, SnackbarProvider, SplitButton, SplitButtonHeadless, Switch, TYPOGRAPHY_ELEMENT_MAP, TYPOGRAPHY_USAGE, Tab, TabList, TabPanel, Tabs, TextField, TimePicker, TimePickerDial, TimePickerInput, Tooltip, TooltipOverlayHeadless, TooltipTrigger, TooltipTriggerHeadless, applyStateLayer, badgeVariants2 as badgeVariants, bottomSheetAnimationVariants, bottomSheetHandlePillVariants, bottomSheetHandleWrapperVariants, bottomSheetScrimVariants, bottomSheetVariants, buttonGroupVariants, calendarCellVariants, cardVariants, chipVariants, clockDialContainerVariants, clockDialNumberVariants, clockHandCenterVariants, clockHandHandleVariants, clockHandTrackVariants, cn, datePickerActionButtonVariants, datePickerActionVariants, datePickerContainerVariants, datePickerDividerVariants, datePickerHeaderVariants, datePickerHeadlineVariants, datePickerNavVariants, datePickerRangeIndicatorVariants, datePickerScrimVariants, datePickerSupportingTextVariants, datePickerWeekdayVariants, dividerVariants, fabMenuItemVariants, fabMenuVariants, generateMD3Theme, getColorValue, getConnectedRadiusClasses, getFontFamily, getMD3Color, getResponsiveTypography, getTypographyClassName, getTypographyForElement, getTypographyStyle, getTypographyToken, hexToRgb, listItemVariants, listVariants, periodSelectorContainerVariants, periodSelectorItemVariants, pxToRem, remToPx, rgbToHex, richTooltipVariants, searchBarVariants, searchViewHeaderVariants, searchViewVariants, sliderActiveTrackVariants, sliderContainerVariants, sliderHandleStateLayerVariants, sliderHandleVariants, sliderInactiveTrackVariants, sliderTrackLayoutVariants, splitButtonContainerVariants, splitButtonDropdownVariants, splitButtonPrimaryVariants, splitButtonVariants, timeInputFieldVariants, timePickerActionButtonVariants, timePickerActionRowVariants, timePickerContainerVariants, timePickerHeadlineVariants, timePickerModeToggleVariants, timeSelectorContainerVariants, timeSeparatorVariants, tooltipVariants, truncateText, useBottomSheetContext, useBottomSheetDrag, useButtonGroup, useDialogContext, useFABMenuContext, useMenuContext, useOptionalButtonGroup, useSnackbar, withOpacity, yearItemVariants };
15070
+ export { AppBar, AppBarHeadless, Badge, BadgeContent, BadgeHeadless, BottomSheet, BottomSheetContext, BottomSheetHandle, BottomSheetHeadless, Button, ButtonGroup, ButtonGroupContext, ButtonGroupHeadless, CalendarCore, Card, CardActions, CardContent, CardHeader, CardHeadless, CardMedia, Checkbox, Chip, ChipHeadless, ChipSet, DateField, DatePicker, DatePickerDocked, DatePickerModal, DatePickerModalInput, Dialog, DialogActions, DialogContent, DialogContext, DialogHeadless, DialogHeadline, Divider, DividerHeadless, Drawer, DrawerIconOnlyContext, DrawerItem, DrawerSection, FAB, FABHeadless, FABMenu, FABMenuContext, FABMenuHeadless, FABMenuItem, HeadlessDrawer, HeadlessDrawerItem, HeadlessMenu, HeadlessMenuDivider, HeadlessMenuItem, HeadlessMenuSection, HeadlessMenuTrigger, HeadlessNavigationBar, HeadlessNavigationBarItem, HeadlessTab, HeadlessTabList, HeadlessTabPanel, IconButton, IconButtonHeadless, List, ListHeadless, ListItem, ListItemHeadless, ListItemLeading, ListItemText, ListItemTrailing, Menu, MenuContext, MenuDivider, MenuItem, MenuSection, MenuTrigger, NavigationBar, NavigationBarItem, Progress, ProgressHeadless, Radio, RadioGroup, RadioGroupHeadless, RadioHeadless, RichTooltip, STATE_LAYER_OPACITY, Search, SearchBar, SearchBarHeadless, SearchView, SearchViewHeadless, Slider, SliderHeadless, Snackbar, SnackbarContext, SnackbarHeadless, SnackbarProvider, SplitButton, SplitButtonHeadless, Switch, TYPOGRAPHY_ELEMENT_MAP, TYPOGRAPHY_USAGE, Tab, TabList, TabPanel, Tabs, TextField, TimePicker, TimePickerDial, TimePickerInput, Tooltip, TooltipOverlayHeadless, TooltipTrigger, TooltipTriggerHeadless, applyStateLayer, badgeVariants2 as badgeVariants, bottomSheetAnimationVariants, bottomSheetHandlePillVariants, bottomSheetHandleWrapperVariants, bottomSheetScrimVariants, bottomSheetVariants, buttonGroupFocusRingVariants, buttonGroupRootVariants, buttonGroupVariants, calendarCellVariants, cardVariants, chipVariants, clockDialContainerVariants, clockDialNumberVariants, clockHandCenterVariants, clockHandHandleVariants, clockHandTrackVariants, cn, datePickerActionButtonVariants, datePickerActionVariants, datePickerContainerVariants, datePickerDividerVariants, datePickerHeaderVariants, datePickerHeadlineVariants, datePickerNavVariants, datePickerRangeIndicatorVariants, datePickerScrimVariants, datePickerSupportingTextVariants, datePickerWeekdayVariants, dividerVariants, fabMenuItemVariants, fabMenuVariants, generateMD3Theme, getColorValue, getConnectedRadiusClasses, getFontFamily, getMD3Color, getResponsiveTypography, getTypographyClassName, getTypographyForElement, getTypographyStyle, getTypographyToken, hexToRgb, listItemVariants, listVariants, periodSelectorContainerVariants, periodSelectorItemVariants, pxToRem, remToPx, rgbToHex, richTooltipVariants, searchBarVariants, searchViewHeaderVariants, searchViewVariants, sliderActiveTrackVariants, sliderContainerVariants, sliderHandleStateLayerVariants, sliderHandleVariants, sliderInactiveTrackVariants, sliderTrackLayoutVariants, splitButtonContainerVariants, splitButtonDropdownVariants, splitButtonPrimaryVariants, splitButtonVariants, timeInputFieldVariants, timePickerActionButtonVariants, timePickerActionRowVariants, timePickerContainerVariants, timePickerHeadlineVariants, timePickerModeToggleVariants, timeSelectorContainerVariants, timeSeparatorVariants, tooltipVariants, truncateText, useBottomSheetContext, useBottomSheetDrag, useButtonGroup, useDialogContext, useFABMenuContext, useMenuContext, useOptionalButtonGroup, useSnackbar, withOpacity, yearItemVariants };
14796
15071
  //# sourceMappingURL=index.js.map
14797
15072
  //# sourceMappingURL=index.js.map