@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.cjs +667 -390
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +330 -198
- package/dist/index.d.ts +330 -198
- package/dist/index.js +668 -393
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -1
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
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,
|
|
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,
|
|
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
|
-
//
|
|
425
|
-
"relative inline-flex items-center justify-center
|
|
426
|
-
"
|
|
427
|
-
// Split MD3 transition: spatial (border-radius)
|
|
428
|
-
// effects (color/bg/shadow)
|
|
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
|
-
|
|
431
|
-
|
|
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
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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-
|
|
462
|
-
medium: "h-10 px-6 text-
|
|
463
|
-
large: "h-
|
|
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
|
|
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
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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,
|
|
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
|
-
...
|
|
828
|
-
|
|
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-
|
|
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
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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
|
-
|
|
853
|
-
|
|
854
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
855
|
-
|
|
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
|
|
944
|
-
|
|
945
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1093
|
-
|
|
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
|
-
|
|
1100
|
-
|
|
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
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
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
|
|
1166
|
+
var iconButtonRootVariants = cva(
|
|
1121
1167
|
[
|
|
1122
|
-
//
|
|
1123
|
-
"relative inline-flex items-center justify-center
|
|
1124
|
-
"
|
|
1125
|
-
|
|
1126
|
-
//
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
"
|
|
1168
|
+
// Layout
|
|
1169
|
+
"relative inline-flex items-center justify-center",
|
|
1170
|
+
"cursor-pointer select-none",
|
|
1171
|
+
"overflow-hidden",
|
|
1172
|
+
// Corner radius driven by CSS variable — set 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
|
-
*
|
|
1213
|
+
* Visual style variant (MD3 icon button types)
|
|
1141
1214
|
*/
|
|
1142
1215
|
variant: {
|
|
1143
|
-
standard: "
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
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
|
|
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
|
-
*
|
|
1231
|
+
* Size tier (M3 Expressive 5-tier)
|
|
1162
1232
|
*/
|
|
1163
1233
|
size: {
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
medium: "h-
|
|
1167
|
-
|
|
1168
|
-
|
|
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
|
-
*
|
|
1241
|
+
* Width variant — adjusts container width
|
|
1173
1242
|
*/
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1243
|
+
width: {
|
|
1244
|
+
narrow: "",
|
|
1245
|
+
default: "",
|
|
1246
|
+
wide: ""
|
|
1177
1247
|
},
|
|
1178
1248
|
/**
|
|
1179
|
-
*
|
|
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
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
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
|
-
//
|
|
1192
|
-
//
|
|
1193
|
-
{
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
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
|
-
|
|
1210
|
-
|
|
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: "
|
|
1344
|
+
variant: "standard",
|
|
1214
1345
|
color: "secondary",
|
|
1215
|
-
|
|
1216
|
-
|
|
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: "
|
|
1357
|
+
variant: "standard",
|
|
1220
1358
|
color: "tertiary",
|
|
1221
|
-
|
|
1222
|
-
|
|
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: "
|
|
1370
|
+
variant: "standard",
|
|
1226
1371
|
color: "error",
|
|
1227
|
-
|
|
1228
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
1237
|
-
|
|
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
|
-
|
|
1243
|
-
|
|
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
|
-
|
|
1249
|
-
|
|
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
|
-
|
|
1255
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
1264
|
-
|
|
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
|
-
|
|
1270
|
-
|
|
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
|
-
|
|
1276
|
-
|
|
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
|
-
|
|
1282
|
-
|
|
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
|
-
//
|
|
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: "
|
|
1289
|
-
|
|
1290
|
-
className:
|
|
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
|
-
|
|
1298
|
-
className:
|
|
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
|
-
|
|
1306
|
-
className:
|
|
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
|
-
|
|
1317
|
-
|
|
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
|
|
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
|
|
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
|
-
//
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
//
|
|
1380
|
-
"
|
|
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
|
-
//
|
|
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
|
-
|
|
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:
|
|
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
|