@brijbyte/agentic-ui 0.0.2 → 0.0.4
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/README.md +132 -35
- package/dist/accordion/accordion.d.ts +15 -1
- package/dist/accordion/accordion.d.ts.map +1 -1
- package/dist/accordion/accordion.js +6 -1
- package/dist/accordion/accordion.js.map +1 -1
- package/dist/accordion/parts.d.ts +1 -1
- package/dist/accordion/parts.js +2 -2
- package/dist/alert-dialog/alert-dialog.d.ts +12 -1
- package/dist/alert-dialog/alert-dialog.d.ts.map +1 -1
- package/dist/alert-dialog/alert-dialog.js +6 -1
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/alert-dialog/parts.d.ts +1 -1
- package/dist/alert-dialog/parts.js +2 -2
- package/dist/badge/badge.d.ts +7 -1
- package/dist/badge/badge.d.ts.map +1 -1
- package/dist/badge/badge.js +4 -0
- package/dist/badge/badge.js.map +1 -1
- package/dist/button/button.css +22 -8
- package/dist/button/button.d.ts +19 -8
- package/dist/button/button.d.ts.map +1 -1
- package/dist/button/button.js +6 -1
- package/dist/button/button.js.map +1 -1
- package/dist/button/button.module.js.map +1 -1
- package/dist/card/card.d.ts +11 -1
- package/dist/card/card.d.ts.map +1 -1
- package/dist/card/card.js +7 -0
- package/dist/card/card.js.map +1 -1
- package/dist/checkbox/checkbox.d.ts +14 -1
- package/dist/checkbox/checkbox.d.ts.map +1 -1
- package/dist/checkbox/checkbox.js +5 -1
- package/dist/checkbox/checkbox.js.map +1 -1
- package/dist/checkbox/parts.js +1 -1
- package/dist/collapsible/collapsible.d.ts +12 -1
- package/dist/collapsible/collapsible.d.ts.map +1 -1
- package/dist/collapsible/collapsible.js +5 -0
- package/dist/collapsible/collapsible.js.map +1 -1
- package/dist/collapsible/parts.js +1 -1
- package/dist/context-menu/context-menu.d.ts +6 -1
- package/dist/context-menu/context-menu.d.ts.map +1 -1
- package/dist/context-menu/context-menu.js +4 -0
- package/dist/context-menu/context-menu.js.map +1 -1
- package/dist/context-menu/parts.js +1 -1
- package/dist/dialog/dialog.d.ts +14 -2
- package/dist/dialog/dialog.d.ts.map +1 -1
- package/dist/dialog/dialog.js +6 -0
- package/dist/dialog/dialog.js.map +1 -1
- package/dist/dialog/parts.js +1 -1
- package/dist/drawer/drawer.d.ts +12 -1
- package/dist/drawer/drawer.d.ts.map +1 -1
- package/dist/drawer/drawer.js +5 -0
- package/dist/drawer/drawer.js.map +1 -1
- package/dist/drawer/parts.d.ts +1 -1
- package/dist/drawer/parts.js +1 -1
- package/dist/index.css +1773 -1316
- package/dist/index.d.ts +29 -20
- package/dist/index.js +50 -37
- package/dist/input/input.d.ts +8 -0
- package/dist/input/input.d.ts.map +1 -1
- package/dist/input/input.js +6 -1
- package/dist/input/input.js.map +1 -1
- package/dist/menu/menu.css +3 -8
- package/dist/menu/menu.d.ts +12 -5
- package/dist/menu/menu.d.ts.map +1 -1
- package/dist/menu/menu.js +10 -24
- package/dist/menu/menu.js.map +1 -1
- package/dist/menu/menu.module.js +1 -1
- package/dist/menu/menu.module.js.map +1 -1
- package/dist/menu/menuitemshortcut.js +1 -1
- package/dist/menu/parts.js +1 -1
- package/dist/meter/circular-meter.d.ts +48 -0
- package/dist/meter/circular-meter.d.ts.map +1 -0
- package/dist/meter/circular-meter.js +86 -0
- package/dist/meter/circular-meter.js.map +1 -0
- package/dist/meter/index.d.ts +4 -0
- package/dist/meter/index.js +5 -0
- package/dist/meter/meter.css +152 -0
- package/dist/meter/meter.d.ts +58 -0
- package/dist/meter/meter.d.ts.map +1 -0
- package/dist/meter/meter.js +50 -0
- package/dist/meter/meter.js.map +1 -0
- package/dist/meter/meter.module.css.d.ts +2 -0
- package/dist/meter/meter.module.js +27 -0
- package/dist/meter/meter.module.js.map +1 -0
- package/dist/meter/meterState.js +18 -0
- package/dist/meter/meterState.js.map +1 -0
- package/dist/meter/parts.d.ts +31 -0
- package/dist/meter/parts.d.ts.map +1 -0
- package/dist/meter/parts.js +56 -0
- package/dist/meter/parts.js.map +1 -0
- package/dist/number-field/number-field.d.ts +17 -1
- package/dist/number-field/number-field.d.ts.map +1 -1
- package/dist/number-field/number-field.js +5 -1
- package/dist/number-field/number-field.js.map +1 -1
- package/dist/number-field/parts.js +1 -1
- package/dist/popover/index.d.ts +3 -0
- package/dist/popover/index.js +4 -0
- package/dist/popover/parts.d.ts +43 -0
- package/dist/popover/parts.d.ts.map +1 -0
- package/dist/popover/parts.js +96 -0
- package/dist/popover/parts.js.map +1 -0
- package/dist/popover/popover.css +173 -0
- package/dist/popover/popover.d.ts +49 -0
- package/dist/popover/popover.d.ts.map +1 -0
- package/dist/popover/popover.js +68 -0
- package/dist/popover/popover.js.map +1 -0
- package/dist/popover/popover.module.css.d.ts +2 -0
- package/dist/popover/popover.module.js +16 -0
- package/dist/popover/popover.module.js.map +1 -0
- package/dist/progress/parts.js +1 -1
- package/dist/progress/progress.d.ts +11 -0
- package/dist/progress/progress.d.ts.map +1 -1
- package/dist/progress/progress.js +5 -0
- package/dist/progress/progress.js.map +1 -1
- package/dist/radio/index.d.ts +3 -0
- package/dist/radio/index.js +4 -0
- package/dist/radio/parts.d.ts +18 -0
- package/dist/radio/parts.d.ts.map +1 -0
- package/dist/radio/parts.js +42 -0
- package/dist/radio/parts.js.map +1 -0
- package/dist/radio/radio.css +84 -0
- package/dist/radio/radio.d.ts +31 -0
- package/dist/radio/radio.d.ts.map +1 -0
- package/dist/radio/radio.js +33 -0
- package/dist/radio/radio.js.map +1 -0
- package/dist/radio/radio.module.css.d.ts +2 -0
- package/dist/radio/radio.module.js +11 -0
- package/dist/radio/radio.module.js.map +1 -0
- package/dist/radio-group/index.d.ts +3 -0
- package/dist/radio-group/index.js +4 -0
- package/dist/radio-group/parts.d.ts +13 -0
- package/dist/radio-group/parts.d.ts.map +1 -0
- package/dist/radio-group/parts.js +31 -0
- package/dist/radio-group/parts.js.map +1 -0
- package/dist/radio-group/radio-group.css +17 -0
- package/dist/radio-group/radio-group.d.ts +37 -0
- package/dist/radio-group/radio-group.d.ts.map +1 -0
- package/dist/radio-group/radio-group.js +28 -0
- package/dist/radio-group/radio-group.js.map +1 -0
- package/dist/radio-group/radio-group.module.css.d.ts +2 -0
- package/dist/radio-group/radio-group.module.js +9 -0
- package/dist/radio-group/radio-group.module.js.map +1 -0
- package/dist/select/parts.js +1 -1
- package/dist/select/select.d.ts +15 -2
- package/dist/select/select.d.ts.map +1 -1
- package/dist/select/select.js +5 -1
- package/dist/select/select.js.map +1 -1
- package/dist/separator/separator.d.ts +4 -0
- package/dist/separator/separator.d.ts.map +1 -1
- package/dist/separator/separator.js +5 -1
- package/dist/separator/separator.js.map +1 -1
- package/dist/shared/PopupArrow.js +22 -0
- package/dist/shared/PopupArrow.js.map +1 -0
- package/dist/slider/parts.js +1 -1
- package/dist/slider/slider.d.ts +19 -1
- package/dist/slider/slider.d.ts.map +1 -1
- package/dist/slider/slider.js +6 -0
- package/dist/slider/slider.js.map +1 -1
- package/dist/styles/tokens.css +21 -8
- package/dist/switch/parts.js +1 -1
- package/dist/switch/switch.css +11 -2
- package/dist/switch/switch.d.ts +13 -1
- package/dist/switch/switch.d.ts.map +1 -1
- package/dist/switch/switch.js +5 -1
- package/dist/switch/switch.js.map +1 -1
- package/dist/switch/switch.module.js.map +1 -1
- package/dist/tabs/parts.js +1 -1
- package/dist/tabs/tabs.d.ts +9 -2
- package/dist/tabs/tabs.d.ts.map +1 -1
- package/dist/tabs/tabs.js +4 -0
- package/dist/tabs/tabs.js.map +1 -1
- package/dist/toast/parts.js +1 -1
- package/dist/toast/toast.d.ts +12 -1
- package/dist/toast/toast.d.ts.map +1 -1
- package/dist/toast/toast.js +8 -0
- package/dist/toast/toast.js.map +1 -1
- package/dist/tokens.css +23 -11
- package/dist/tooltip/parts.js +1 -1
- package/dist/tooltip/tooltip.d.ts +10 -1
- package/dist/tooltip/tooltip.d.ts.map +1 -1
- package/dist/tooltip/tooltip.js +4 -0
- package/dist/tooltip/tooltip.js.map +1 -1
- package/package.json +23 -2
- package/src/accordion/accordion.tsx +14 -0
- package/src/alert-dialog/alert-dialog.tsx +11 -0
- package/src/badge/badge.tsx +6 -0
- package/src/button/button.module.css +29 -13
- package/src/button/button.tsx +19 -8
- package/src/card/card.tsx +10 -0
- package/src/checkbox/checkbox.tsx +13 -0
- package/src/collapsible/collapsible.tsx +11 -0
- package/src/context-menu/context-menu.tsx +5 -0
- package/src/dialog/dialog.tsx +13 -1
- package/src/drawer/drawer.tsx +11 -0
- package/src/index.ts +25 -233
- package/src/input/input.tsx +8 -0
- package/src/menu/menu.module.css +3 -10
- package/src/menu/menu.tsx +13 -26
- package/src/meter/circular-meter.tsx +114 -0
- package/src/meter/index.ts +9 -0
- package/src/meter/meter.module.css +162 -0
- package/src/meter/meter.tsx +86 -0
- package/src/meter/meterState.ts +29 -0
- package/src/meter/parts.tsx +72 -0
- package/src/number-field/number-field.tsx +16 -0
- package/src/popover/index.ts +14 -0
- package/src/popover/parts.tsx +120 -0
- package/src/popover/popover.module.css +189 -0
- package/src/popover/popover.tsx +80 -0
- package/src/progress/progress.tsx +11 -0
- package/src/radio/index.ts +6 -0
- package/src/radio/parts.tsx +43 -0
- package/src/radio/radio.module.css +96 -0
- package/src/radio/radio.tsx +37 -0
- package/src/radio-group/index.ts +5 -0
- package/src/radio-group/parts.tsx +32 -0
- package/src/radio-group/radio-group.module.css +17 -0
- package/src/radio-group/radio-group.tsx +63 -0
- package/src/select/select.tsx +14 -1
- package/src/separator/separator.tsx +4 -0
- package/src/shared/PopupArrow.tsx +41 -0
- package/src/slider/slider.tsx +18 -0
- package/src/styles/tokens.css +23 -11
- package/src/switch/switch.module.css +11 -2
- package/src/switch/switch.tsx +12 -0
- package/src/tabs/tabs.tsx +8 -1
- package/src/toast/toast.tsx +11 -0
- package/src/tooltip/tooltip.tsx +9 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styled primitives for Radio (single item).
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import { RadioGroup } from '@base-ui/react/radio-group';
|
|
7
|
+
* import { RadioRoot, RadioIndicator } from '@brijbyte/agentic-ui/radio';
|
|
8
|
+
*
|
|
9
|
+
* <RadioGroup defaultValue="a">
|
|
10
|
+
* <label htmlFor="opt-a">
|
|
11
|
+
* <RadioRoot id="opt-a" value="a">
|
|
12
|
+
* <RadioIndicator />
|
|
13
|
+
* </RadioRoot>
|
|
14
|
+
* Option A
|
|
15
|
+
* </label>
|
|
16
|
+
* </RadioGroup>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import { forwardRef } from "react";
|
|
20
|
+
import type { ComponentRef, ComponentPropsWithoutRef } from "react";
|
|
21
|
+
import { Radio as BaseRadio } from "@base-ui/react/radio";
|
|
22
|
+
import styles from "./radio.module.css";
|
|
23
|
+
|
|
24
|
+
type BaseRootProps = ComponentPropsWithoutRef<typeof BaseRadio.Root>;
|
|
25
|
+
type BaseIndicatorProps = ComponentPropsWithoutRef<typeof BaseRadio.Indicator>;
|
|
26
|
+
|
|
27
|
+
export interface RadioRootProps extends Omit<BaseRootProps, "className"> {
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface RadioIndicatorProps extends Omit<BaseIndicatorProps, "className"> {
|
|
31
|
+
className?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const RadioRoot = forwardRef<ComponentRef<typeof BaseRadio.Root>, RadioRootProps>(function RadioRoot({ className, ...props }, ref) {
|
|
35
|
+
return <BaseRadio.Root ref={ref} className={`${styles.radio} ${className ?? ""}`} {...props} />;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const RadioIndicator = forwardRef<ComponentRef<typeof BaseRadio.Indicator>, RadioIndicatorProps>(function RadioIndicator(
|
|
39
|
+
{ className, ...props },
|
|
40
|
+
ref,
|
|
41
|
+
) {
|
|
42
|
+
return <BaseRadio.Indicator ref={ref} keepMounted className={`${styles.indicator} ${className ?? ""}`} {...props} />;
|
|
43
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* ── Single radio item layout ───────────────────────────────────── */
|
|
3
|
+
|
|
4
|
+
.item {
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
gap: var(--space-2);
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
user-select: none;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.item:has([data-disabled]) {
|
|
13
|
+
cursor: not-allowed;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.item:has([data-disabled]) .label {
|
|
17
|
+
opacity: 0.44;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* ── Radio button (the circle) ──────────────────────────────────── */
|
|
21
|
+
|
|
22
|
+
.radio {
|
|
23
|
+
flex-shrink: 0;
|
|
24
|
+
width: 16px;
|
|
25
|
+
height: 16px;
|
|
26
|
+
border-radius: var(--radius-full);
|
|
27
|
+
border: var(--border-width-base) solid var(--color-line-strong);
|
|
28
|
+
background-color: var(--color-surface-1);
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
transition:
|
|
33
|
+
background-color var(--duration-fast) var(--easing-standard),
|
|
34
|
+
border-color var(--duration-fast) var(--easing-standard),
|
|
35
|
+
box-shadow var(--duration-fast) var(--easing-standard);
|
|
36
|
+
outline: none;
|
|
37
|
+
position: relative;
|
|
38
|
+
/* Reset button/span defaults */
|
|
39
|
+
padding: 0;
|
|
40
|
+
margin: 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.radio:focus-visible {
|
|
44
|
+
box-shadow: var(--shadow-focus);
|
|
45
|
+
border-color: var(--color-accent);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.radio:hover:not([data-disabled]) {
|
|
49
|
+
border-color: var(--color-accent);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.radio[data-checked] {
|
|
53
|
+
background-color: var(--color-accent);
|
|
54
|
+
border-color: var(--color-accent);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.radio[data-checked]:hover:not([data-disabled]) {
|
|
58
|
+
background-color: var(--color-accent-hover);
|
|
59
|
+
border-color: var(--color-accent-hover);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.radio[data-disabled] {
|
|
63
|
+
opacity: 0.44;
|
|
64
|
+
cursor: not-allowed;
|
|
65
|
+
pointer-events: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ── Indicator (inner dot) ──────────────────────────────────────── */
|
|
69
|
+
|
|
70
|
+
.indicator {
|
|
71
|
+
width: 6px;
|
|
72
|
+
height: 6px;
|
|
73
|
+
border-radius: var(--radius-full);
|
|
74
|
+
background-color: var(--color-on-accent);
|
|
75
|
+
transform: scale(0);
|
|
76
|
+
transition:
|
|
77
|
+
transform var(--duration-fast) var(--easing-spring),
|
|
78
|
+
opacity var(--duration-fast) var(--easing-standard);
|
|
79
|
+
opacity: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* data-checked is on the Root; the Indicator inherits it */
|
|
83
|
+
.radio[data-checked] .indicator {
|
|
84
|
+
transform: scale(1);
|
|
85
|
+
opacity: 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* ── Label text ─────────────────────────────────────────────────── */
|
|
89
|
+
|
|
90
|
+
.label {
|
|
91
|
+
font-family: var(--font-mono);
|
|
92
|
+
font-size: var(--font-size-sm);
|
|
93
|
+
color: var(--color-primary);
|
|
94
|
+
line-height: var(--line-height-normal);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useId } from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import { Radio as BaseRadio } from "@base-ui/react/radio";
|
|
4
|
+
import styles from "./radio.module.css";
|
|
5
|
+
|
|
6
|
+
export interface RadioProps {
|
|
7
|
+
/** Value submitted with the form and matched against the group's value. */
|
|
8
|
+
value: string;
|
|
9
|
+
/** Label rendered next to the button. */
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
readOnly?: boolean;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
/** Override the auto-generated element id. */
|
|
15
|
+
id?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A single radio button with an optional label.
|
|
21
|
+
* Must be placed inside `<RadioGroup>` or a raw base-ui RadioGroup.
|
|
22
|
+
*/
|
|
23
|
+
export function Radio({ value, children, id, className, ...props }: RadioProps) {
|
|
24
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
25
|
+
const radioId = id ?? useId();
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<label className={`${styles.item} ${className ?? ""}`} htmlFor={radioId}>
|
|
29
|
+
<BaseRadio.Root id={radioId} value={value} className={styles.radio} {...props}>
|
|
30
|
+
<BaseRadio.Indicator keepMounted className={styles.indicator} />
|
|
31
|
+
</BaseRadio.Root>
|
|
32
|
+
{children && <span className={styles.label}>{children}</span>}
|
|
33
|
+
</label>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { styles as RadioStyles };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styled primitive for RadioGroup.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import { Radio } from '@brijbyte/agentic-ui/radio';
|
|
7
|
+
* import { RadioGroupRoot } from '@brijbyte/agentic-ui/radio-group';
|
|
8
|
+
*
|
|
9
|
+
* <RadioGroupRoot defaultValue="b" name="plan">
|
|
10
|
+
* <Radio value="a">Hobby</Radio>
|
|
11
|
+
* <Radio value="b">Pro</Radio>
|
|
12
|
+
* <Radio value="c">Enterprise</Radio>
|
|
13
|
+
* </RadioGroupRoot>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import { forwardRef } from "react";
|
|
17
|
+
import type { ComponentRef, ComponentPropsWithoutRef } from "react";
|
|
18
|
+
import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
|
|
19
|
+
import styles from "./radio-group.module.css";
|
|
20
|
+
|
|
21
|
+
type BaseGroupProps = ComponentPropsWithoutRef<typeof BaseRadioGroup>;
|
|
22
|
+
|
|
23
|
+
export interface RadioGroupRootProps extends Omit<BaseGroupProps, "className"> {
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const RadioGroupRoot = forwardRef<ComponentRef<typeof BaseRadioGroup>, RadioGroupRootProps>(function RadioGroupRoot(
|
|
28
|
+
{ className, ...props },
|
|
29
|
+
ref,
|
|
30
|
+
) {
|
|
31
|
+
return <BaseRadioGroup ref={ref} className={`${styles.group} ${className ?? ""}`} {...props} />;
|
|
32
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.group {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: var(--space-2);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.group-label {
|
|
9
|
+
font-family: var(--font-mono);
|
|
10
|
+
font-size: var(--font-size-xs);
|
|
11
|
+
font-weight: var(--font-weight-semibold);
|
|
12
|
+
color: var(--color-tertiary);
|
|
13
|
+
text-transform: uppercase;
|
|
14
|
+
letter-spacing: var(--letter-spacing-wide);
|
|
15
|
+
margin-bottom: var(--space-1);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useId } from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
|
|
4
|
+
import { Radio } from "../radio/radio";
|
|
5
|
+
import styles from "./radio-group.module.css";
|
|
6
|
+
|
|
7
|
+
export interface RadioOption {
|
|
8
|
+
value: string;
|
|
9
|
+
label: ReactNode;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface RadioGroupProps {
|
|
14
|
+
/** The options to render. Each becomes one `<Radio>` item. */
|
|
15
|
+
options: RadioOption[];
|
|
16
|
+
/** Accessible group label rendered above the options. */
|
|
17
|
+
label?: ReactNode;
|
|
18
|
+
/** Controlled selected value. */
|
|
19
|
+
value?: string;
|
|
20
|
+
/** Initial selected value (uncontrolled). */
|
|
21
|
+
defaultValue?: string;
|
|
22
|
+
onValueChange?: (value: string, eventDetails: unknown) => void;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
readOnly?: boolean;
|
|
25
|
+
required?: boolean;
|
|
26
|
+
/** HTML name for form submission. */
|
|
27
|
+
name?: string;
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A labelled group of radio buttons. Renders a base-ui RadioGroup with one
|
|
33
|
+
* `<Radio>` per option.
|
|
34
|
+
*
|
|
35
|
+
* For full control over layout or behaviour use `RadioGroupRoot` with
|
|
36
|
+
* individual `<Radio>` or `<RadioRoot>` elements.
|
|
37
|
+
*/
|
|
38
|
+
export { styles as RadioGroupStyles };
|
|
39
|
+
|
|
40
|
+
export function RadioGroup({ options, label, className, onValueChange, ...props }: RadioGroupProps) {
|
|
41
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
42
|
+
const labelId = useId();
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<BaseRadioGroup
|
|
46
|
+
aria-labelledby={label ? labelId : undefined}
|
|
47
|
+
className={`${styles.group} ${className ?? ""}`}
|
|
48
|
+
onValueChange={onValueChange as never}
|
|
49
|
+
{...props}
|
|
50
|
+
>
|
|
51
|
+
{label && (
|
|
52
|
+
<div id={labelId} className={styles["group-label"]}>
|
|
53
|
+
{label}
|
|
54
|
+
</div>
|
|
55
|
+
)}
|
|
56
|
+
{options.map((opt) => (
|
|
57
|
+
<Radio key={opt.value} value={opt.value} {...(opt.disabled !== undefined && { disabled: opt.disabled })}>
|
|
58
|
+
{opt.label}
|
|
59
|
+
</Radio>
|
|
60
|
+
))}
|
|
61
|
+
</BaseRadioGroup>
|
|
62
|
+
);
|
|
63
|
+
}
|
package/src/select/select.tsx
CHANGED
|
@@ -14,17 +14,26 @@ export interface SelectGroup {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface SelectProps {
|
|
17
|
+
/** Currently selected value (controlled). */
|
|
17
18
|
value?: string;
|
|
19
|
+
/** Initially selected value (uncontrolled). */
|
|
18
20
|
defaultValue?: string;
|
|
19
|
-
/** `eventDetails` is the base-ui event details object. Value may be null when cleared. */
|
|
21
|
+
/** Called when the selection changes. `eventDetails` is the base-ui event details object. Value may be null when cleared. */
|
|
20
22
|
onValueChange?: (value: string | null, eventDetails: unknown) => void;
|
|
23
|
+
/** Prevent interaction. */
|
|
21
24
|
disabled?: boolean;
|
|
25
|
+
/** Mark the field as required for form validation. */
|
|
22
26
|
required?: boolean;
|
|
27
|
+
/** HTML name attribute for form submission. */
|
|
23
28
|
name?: string;
|
|
29
|
+
/** Text shown when no value is selected. */
|
|
24
30
|
placeholder?: string;
|
|
31
|
+
/** Flat list of options (use `groups` for grouped options). */
|
|
25
32
|
options?: SelectOption[];
|
|
33
|
+
/** Grouped options with optional section labels. */
|
|
26
34
|
groups?: SelectGroup[];
|
|
27
35
|
className?: string;
|
|
36
|
+
/** Override the auto-generated element id. */
|
|
28
37
|
id?: string;
|
|
29
38
|
}
|
|
30
39
|
|
|
@@ -55,6 +64,10 @@ function SelectItem({ option }: { option: SelectOption }) {
|
|
|
55
64
|
);
|
|
56
65
|
}
|
|
57
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Dropdown select with keyboard navigation, grouping, and search. Pass
|
|
69
|
+
* `options` for a flat list or `groups` for sections with optional labels.
|
|
70
|
+
*/
|
|
58
71
|
export function Select({ placeholder = "Select…", options, groups, className, onValueChange, value, defaultValue, ...props }: SelectProps) {
|
|
59
72
|
const allOptions = useMemo(() => [...(options ?? []), ...(groups?.flatMap((g) => g.options) ?? [])], [options, groups]);
|
|
60
73
|
|
|
@@ -11,6 +11,10 @@ export interface SeparatorProps extends Omit<BaseSeparatorProps, "className"> {
|
|
|
11
11
|
className?: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* A semantic divider accessible to screen readers. Renders a horizontal
|
|
16
|
+
* line by default; switch to vertical for inline layouts.
|
|
17
|
+
*/
|
|
14
18
|
export const Separator = forwardRef<ComponentRef<typeof BaseSeparator>, SeparatorProps>(function Separator(
|
|
15
19
|
{ className, orientation = "horizontal", ...props },
|
|
16
20
|
ref,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared arrow SVG used by Menu and Popover.
|
|
3
|
+
*
|
|
4
|
+
* Two paths:
|
|
5
|
+
* 1. Fill — the arrow body, matches the popup surface colour.
|
|
6
|
+
* 2. Seam — a thin strip in the border colour at the base, covering
|
|
7
|
+
* the popup border at the junction so it doesn't bleed through.
|
|
8
|
+
*
|
|
9
|
+
* All CSS classes come from the importing component's own CSS module
|
|
10
|
+
* so the rules are bundled into the component's CSS file, not a
|
|
11
|
+
* separate shared chunk that consumers would need to import separately.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <BaseMenu.Arrow className={styles.arrow}>
|
|
16
|
+
* <PopupArrow fillClass={styles["arrow-fill"]!} seamClass={styles["arrow-seam"]!} />
|
|
17
|
+
* </BaseMenu.Arrow>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
interface PopupArrowProps {
|
|
22
|
+
fillClass: string;
|
|
23
|
+
seamClass: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function PopupArrow({ fillClass, seamClass }: PopupArrowProps) {
|
|
27
|
+
return (
|
|
28
|
+
<svg width="20" height="10" viewBox="0 0 20 10" fill="none" aria-hidden>
|
|
29
|
+
{/* Body — surface colour */}
|
|
30
|
+
<path
|
|
31
|
+
d="M9.66437 2.60207L4.80758 6.97318C4.07308 7.63423 3.11989 8 2.13172 8H0V10H20V8H18.5349C17.5468 8 16.5936 7.63423 15.8591 6.97318L11.0023 2.60207C10.622 2.2598 10.0447 2.25979 9.66437 2.60207Z"
|
|
32
|
+
className={fillClass}
|
|
33
|
+
/>
|
|
34
|
+
{/* Seam — border colour strip at the base, covers the popup border at the junction */}
|
|
35
|
+
<path
|
|
36
|
+
d="M10.3333 3.34539L5.47654 7.71648C4.55842 8.54279 3.36693 9 2.13172 9H0V8H2.13172C3.11989 8 4.07308 7.63423 4.80758 6.97318L9.66437 2.60207C10.0447 2.25979 10.622 2.2598 11.0023 2.60207L15.8591 6.97318C16.5936 7.63423 17.5468 8 18.5349 8H20V9H18.5349C17.2998 9 16.1083 8.54278 15.1901 7.71648L10.3333 3.34539Z"
|
|
37
|
+
className={seamClass}
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
}
|
package/src/slider/slider.tsx
CHANGED
|
@@ -3,17 +3,29 @@ import { Slider as BaseSlider } from "@base-ui/react/slider";
|
|
|
3
3
|
import styles from "./slider.module.css";
|
|
4
4
|
|
|
5
5
|
export interface SliderProps {
|
|
6
|
+
/** Current value (controlled). Pass an array for range sliders. */
|
|
6
7
|
value?: number | number[];
|
|
8
|
+
/** Initial value (uncontrolled). Pass an array for range sliders. */
|
|
7
9
|
defaultValue?: number | number[];
|
|
10
|
+
/** Called on every value change while dragging. */
|
|
8
11
|
onValueChange?: (value: number | number[], eventDetails: unknown) => void;
|
|
12
|
+
/** Called once when the user finishes dragging. */
|
|
9
13
|
onValueCommitted?: (value: number | number[], eventDetails: unknown) => void;
|
|
14
|
+
/** Minimum allowed value. @default 0 */
|
|
10
15
|
min?: number;
|
|
16
|
+
/** Maximum allowed value. @default 100 */
|
|
11
17
|
max?: number;
|
|
18
|
+
/** Step increment. @default 1 */
|
|
12
19
|
step?: number;
|
|
20
|
+
/** Step used for Page Up / Page Down keyboard shortcuts. @default 10 */
|
|
13
21
|
largeStep?: number;
|
|
22
|
+
/** Prevent interaction. */
|
|
14
23
|
disabled?: boolean;
|
|
24
|
+
/** HTML name attribute for form submission. */
|
|
15
25
|
name?: string;
|
|
26
|
+
/** Axis direction. @default "horizontal" */
|
|
16
27
|
orientation?: "horizontal" | "vertical";
|
|
28
|
+
/** `Intl.NumberFormatOptions` for value display formatting. */
|
|
17
29
|
format?: Intl.NumberFormatOptions;
|
|
18
30
|
/** Visible label rendered above the track. */
|
|
19
31
|
label?: ReactNode;
|
|
@@ -24,6 +36,12 @@ export interface SliderProps {
|
|
|
24
36
|
className?: string;
|
|
25
37
|
}
|
|
26
38
|
|
|
39
|
+
/**
|
|
40
|
+
* An accessible range input with full keyboard and touch support. Pass a
|
|
41
|
+
* single number for a standard slider or an array for a range slider with
|
|
42
|
+
* two thumbs. Supports steps, large steps (Page Up/Down), and
|
|
43
|
+
* `Intl.NumberFormat` display formatting.
|
|
44
|
+
*/
|
|
27
45
|
export function Slider({
|
|
28
46
|
label,
|
|
29
47
|
showValue = false,
|
package/src/styles/tokens.css
CHANGED
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
* Monospace-first, semantic color tokens, supports light & dark modes.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
/* Establish layer order — must come before any @layer usage */
|
|
9
|
-
@layer theme, base, components, utilities;
|
|
10
|
-
|
|
11
8
|
@layer theme {
|
|
12
9
|
:root {
|
|
13
10
|
/* ─── Typography ──────────────────────────────────────────────── */
|
|
@@ -146,7 +143,7 @@
|
|
|
146
143
|
|
|
147
144
|
/* Text */
|
|
148
145
|
--color-primary: rgba(0, 0, 0, 0.88);
|
|
149
|
-
--color-secondary: rgba(0, 0, 0, 0.
|
|
146
|
+
--color-secondary: rgba(0, 0, 0, 0.6); /* raised from 0.55 — AA 5.01:1 on hover bg */
|
|
150
147
|
--color-tertiary: rgba(0, 0, 0, 0.36);
|
|
151
148
|
--color-disabled: rgba(0, 0, 0, 0.24);
|
|
152
149
|
--color-inverse: rgba(255, 255, 255, 0.95);
|
|
@@ -170,6 +167,8 @@
|
|
|
170
167
|
--color-accent: #0078d4;
|
|
171
168
|
--color-accent-hover: #006bbf;
|
|
172
169
|
--color-accent-pressed: #005ea8;
|
|
170
|
+
--color-accent-solid: #0078d4; /* solid button bg — same as accent in light (4.83:1 vs white) */
|
|
171
|
+
--color-accent-text: #005ea8; /* text/icon on tinted surfaces — AA 5.09:1 on accent-tint bg */
|
|
173
172
|
--color-accent-tint: rgba(0, 120, 212, 0.1);
|
|
174
173
|
--color-accent-tint-hover: rgba(0, 120, 212, 0.16);
|
|
175
174
|
|
|
@@ -190,20 +189,23 @@
|
|
|
190
189
|
/* Status — Success */
|
|
191
190
|
--color-success-bg: #f0fdf4;
|
|
192
191
|
--color-success-border: #bbf7d0;
|
|
193
|
-
--color-success-text: #15803d
|
|
194
|
-
--color-success-solid: #16a34a
|
|
192
|
+
--color-success-text: #147a39; /* darkened from #15803d — AA 4.73:1 on canvas */
|
|
193
|
+
--color-success-solid: #15803d; /* darkened from #16a34a — AA 5.02:1 vs white */
|
|
194
|
+
--color-success-on-solid: #ffffff;
|
|
195
195
|
|
|
196
196
|
/* Status — Warning */
|
|
197
197
|
--color-warning-bg: #fffbeb;
|
|
198
198
|
--color-warning-border: #fde68a;
|
|
199
199
|
--color-warning-text: #92400e;
|
|
200
|
-
--color-warning-solid: #d97706
|
|
200
|
+
--color-warning-solid: #b45309; /* darkened from #d97706 — AA 5.02:1 vs white */
|
|
201
|
+
--color-warning-on-solid: #ffffff;
|
|
201
202
|
|
|
202
203
|
/* Status — Error */
|
|
203
204
|
--color-error-bg: #fef2f2;
|
|
204
205
|
--color-error-border: #fecaca;
|
|
205
206
|
--color-error-text: #991b1b;
|
|
206
207
|
--color-error-solid: #dc2626;
|
|
208
|
+
--color-error-on-solid: #ffffff;
|
|
207
209
|
|
|
208
210
|
/* Status — Info */
|
|
209
211
|
--color-info-bg: #eff6ff;
|
|
@@ -268,6 +270,8 @@
|
|
|
268
270
|
--color-accent: #0a84ff;
|
|
269
271
|
--color-accent-hover: #0071e3;
|
|
270
272
|
--color-accent-pressed: #005bb5;
|
|
273
|
+
--color-accent-solid: #0071e3; /* solid button bg — darkened from #0a84ff — AA 4.70:1 vs white */
|
|
274
|
+
--color-accent-text: #60a5fa; /* text/icon on tinted surfaces — AA 5.87:1 on accent-tint bg */
|
|
271
275
|
--color-accent-tint: rgba(10, 132, 255, 0.12);
|
|
272
276
|
--color-accent-tint-hover: rgba(10, 132, 255, 0.2);
|
|
273
277
|
|
|
@@ -289,19 +293,22 @@
|
|
|
289
293
|
--color-success-bg: rgba(22, 163, 74, 0.12);
|
|
290
294
|
--color-success-border: rgba(22, 163, 74, 0.3);
|
|
291
295
|
--color-success-text: #4ade80;
|
|
292
|
-
--color-success-solid: #22c55e;
|
|
296
|
+
--color-success-solid: #22c55e; /* vivid — AA 9.22:1 vs black text */
|
|
297
|
+
--color-success-on-solid: #000000; /* dark text preserves vibrancy */
|
|
293
298
|
|
|
294
299
|
/* Status — Warning */
|
|
295
300
|
--color-warning-bg: rgba(217, 119, 6, 0.12);
|
|
296
301
|
--color-warning-border: rgba(217, 119, 6, 0.3);
|
|
297
302
|
--color-warning-text: #fbbf24;
|
|
298
|
-
--color-warning-solid: #f59e0b;
|
|
303
|
+
--color-warning-solid: #f59e0b; /* vivid — AA 9.78:1 vs black text */
|
|
304
|
+
--color-warning-on-solid: #000000; /* dark text preserves vibrancy */
|
|
299
305
|
|
|
300
306
|
/* Status — Error */
|
|
301
307
|
--color-error-bg: rgba(220, 38, 38, 0.12);
|
|
302
308
|
--color-error-border: rgba(220, 38, 38, 0.3);
|
|
303
309
|
--color-error-text: #f87171;
|
|
304
|
-
--color-error-solid: #ef4444
|
|
310
|
+
--color-error-solid: #dc2626; /* darkened from #ef4444 — AA 4.83:1 vs white */
|
|
311
|
+
--color-error-on-solid: #ffffff;
|
|
305
312
|
|
|
306
313
|
/* Status — Info */
|
|
307
314
|
--color-info-bg: rgba(37, 99, 235, 0.12);
|
|
@@ -355,6 +362,8 @@
|
|
|
355
362
|
--color-accent: #0a84ff;
|
|
356
363
|
--color-accent-hover: #0071e3;
|
|
357
364
|
--color-accent-pressed: #005bb5;
|
|
365
|
+
--color-accent-solid: #0071e3;
|
|
366
|
+
--color-accent-text: #60a5fa;
|
|
358
367
|
--color-accent-tint: rgba(10, 132, 255, 0.12);
|
|
359
368
|
--color-accent-tint-hover: rgba(10, 132, 255, 0.2);
|
|
360
369
|
|
|
@@ -374,16 +383,19 @@
|
|
|
374
383
|
--color-success-border: rgba(22, 163, 74, 0.3);
|
|
375
384
|
--color-success-text: #4ade80;
|
|
376
385
|
--color-success-solid: #22c55e;
|
|
386
|
+
--color-success-on-solid: #000000;
|
|
377
387
|
|
|
378
388
|
--color-warning-bg: rgba(217, 119, 6, 0.12);
|
|
379
389
|
--color-warning-border: rgba(217, 119, 6, 0.3);
|
|
380
390
|
--color-warning-text: #fbbf24;
|
|
381
391
|
--color-warning-solid: #f59e0b;
|
|
392
|
+
--color-warning-on-solid: #000000;
|
|
382
393
|
|
|
383
394
|
--color-error-bg: rgba(220, 38, 38, 0.12);
|
|
384
395
|
--color-error-border: rgba(220, 38, 38, 0.3);
|
|
385
396
|
--color-error-text: #f87171;
|
|
386
|
-
--color-error-solid: #
|
|
397
|
+
--color-error-solid: #dc2626;
|
|
398
|
+
--color-error-on-solid: #ffffff;
|
|
387
399
|
|
|
388
400
|
--color-info-bg: rgba(37, 99, 235, 0.12);
|
|
389
401
|
--color-info-border: rgba(37, 99, 235, 0.3);
|
|
@@ -6,10 +6,14 @@
|
|
|
6
6
|
cursor: pointer;
|
|
7
7
|
user-select: none;
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
/* data-disabled lives on the inner button, not the label wrapper.
|
|
10
|
+
Use :has() to dim the label text, and target the track directly. */
|
|
11
|
+
.root:has([data-disabled]) {
|
|
11
12
|
cursor: not-allowed;
|
|
12
13
|
}
|
|
14
|
+
.root:has([data-disabled]) .label {
|
|
15
|
+
opacity: 0.44;
|
|
16
|
+
}
|
|
13
17
|
.thumb-track {
|
|
14
18
|
position: relative;
|
|
15
19
|
width: 36px;
|
|
@@ -24,6 +28,11 @@
|
|
|
24
28
|
outline: none;
|
|
25
29
|
flex-shrink: 0;
|
|
26
30
|
}
|
|
31
|
+
.thumb-track[data-disabled] {
|
|
32
|
+
opacity: 0.44;
|
|
33
|
+
cursor: not-allowed;
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
27
36
|
.thumb-track:focus-visible {
|
|
28
37
|
box-shadow: var(--shadow-focus);
|
|
29
38
|
}
|
package/src/switch/switch.tsx
CHANGED
|
@@ -4,19 +4,31 @@ import { Switch as BaseSwitch } from "@base-ui/react/switch";
|
|
|
4
4
|
import styles from "./switch.module.css";
|
|
5
5
|
|
|
6
6
|
export interface SwitchProps {
|
|
7
|
+
/** Controlled checked state. */
|
|
7
8
|
checked?: boolean;
|
|
9
|
+
/** Initial checked state (uncontrolled). */
|
|
8
10
|
defaultChecked?: boolean;
|
|
11
|
+
/** Prevent interaction. */
|
|
9
12
|
disabled?: boolean;
|
|
13
|
+
/** Mark the field as required for form validation. */
|
|
10
14
|
required?: boolean;
|
|
15
|
+
/** HTML name attribute for form submission. */
|
|
11
16
|
name?: string;
|
|
17
|
+
/** HTML value attribute for form submission. */
|
|
12
18
|
value?: string;
|
|
13
19
|
/** Called when checked state changes. `eventDetails` is the base-ui event details object. */
|
|
14
20
|
onCheckedChange?: (checked: boolean, eventDetails: unknown) => void;
|
|
21
|
+
/** Label content rendered next to the switch. */
|
|
15
22
|
children?: ReactNode;
|
|
23
|
+
/** Override the auto-generated element id. */
|
|
16
24
|
id?: string;
|
|
17
25
|
className?: string;
|
|
18
26
|
}
|
|
19
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Toggle for boolean settings. Renders a track with a sliding thumb and
|
|
30
|
+
* an optional label. Wraps `@base-ui/react` Switch.
|
|
31
|
+
*/
|
|
20
32
|
export function Switch({ children, id, className, onCheckedChange, ...props }: SwitchProps) {
|
|
21
33
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
22
34
|
const switchId = id ?? useId();
|
package/src/tabs/tabs.tsx
CHANGED
|
@@ -11,14 +11,21 @@ export interface TabItem {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface TabsProps {
|
|
14
|
+
/** Array of tab definitions to render. */
|
|
14
15
|
items: TabItem[];
|
|
16
|
+
/** Currently active tab value (controlled). */
|
|
15
17
|
value?: string;
|
|
18
|
+
/** Initially active tab value (uncontrolled). Defaults to the first item. */
|
|
16
19
|
defaultValue?: string;
|
|
17
|
-
/** `eventDetails` is the base-ui event details object. */
|
|
20
|
+
/** Called when the active tab changes. `eventDetails` is the base-ui event details object. */
|
|
18
21
|
onValueChange?: (value: unknown, eventDetails: unknown) => void;
|
|
19
22
|
className?: string;
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Tab navigation for switching between content panels. Each tab can have
|
|
27
|
+
* an optional icon and can be individually disabled.
|
|
28
|
+
*/
|
|
22
29
|
export function Tabs({ items, className, ...props }: TabsProps) {
|
|
23
30
|
const defaultVal = props.defaultValue ?? items[0]?.value;
|
|
24
31
|
|
package/src/toast/toast.tsx
CHANGED
|
@@ -77,8 +77,11 @@ const DEFAULT_LIMIT: Record<NonNullable<ToastViewportProps["variant"]>, number>
|
|
|
77
77
|
|
|
78
78
|
export interface ToastProviderProps {
|
|
79
79
|
children: ReactNode;
|
|
80
|
+
/** Layout style for the viewport. @default "list" */
|
|
80
81
|
variant?: ToastViewportProps["variant"];
|
|
82
|
+
/** Maximum number of toasts shown at once. */
|
|
81
83
|
limit?: number;
|
|
84
|
+
/** Auto-dismiss delay in milliseconds. */
|
|
82
85
|
timeout?: number;
|
|
83
86
|
}
|
|
84
87
|
|
|
@@ -91,6 +94,10 @@ const MAX_LIMIT: Record<NonNullable<ToastViewportProps["variant"]>, number> = {
|
|
|
91
94
|
list: 5,
|
|
92
95
|
};
|
|
93
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Drop-in provider that wires limit defaults to the chosen viewport variant.
|
|
99
|
+
* Use this instead of base-ui's `Toast.Provider` when using `ToastViewport`.
|
|
100
|
+
*/
|
|
94
101
|
export function ToastProvider({ children, variant = "list", limit, timeout }: ToastProviderProps) {
|
|
95
102
|
const resolvedLimit = Math.min(limit ?? DEFAULT_LIMIT[variant], MAX_LIMIT[variant]);
|
|
96
103
|
return (
|
|
@@ -100,6 +107,10 @@ export function ToastProvider({ children, variant = "list", limit, timeout }: To
|
|
|
100
107
|
);
|
|
101
108
|
}
|
|
102
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Renders and manages toast notifications. Supports `"stacked"` (Sonner-style
|
|
112
|
+
* fanned cards) and `"list"` (vertically stacked, each fully visible) layouts.
|
|
113
|
+
*/
|
|
103
114
|
export function ToastViewport({ variant = "list", limit: _limit }: ToastViewportProps) {
|
|
104
115
|
const manager = useToastManager();
|
|
105
116
|
const isStacked = variant === "stacked";
|