@usefragments/ui 1.0.2 → 1.1.1
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 +16 -16
- package/dist/assets/fragments-wordmark.cjs +30 -0
- package/dist/assets/fragments-wordmark.d.ts +13 -0
- package/dist/assets/fragments-wordmark.d.ts.map +1 -0
- package/dist/assets/fragments-wordmark.js +30 -0
- package/dist/assets/ui.css +3173 -3108
- package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
- package/dist/components/Accordion/Accordion.module.scss.js +8 -8
- package/dist/components/Accordion/index.cjs +22 -10
- package/dist/components/Accordion/index.d.ts.map +1 -1
- package/dist/components/Accordion/index.js +22 -10
- package/dist/components/Alert/Alert.module.scss.cjs +13 -13
- package/dist/components/Alert/Alert.module.scss.js +13 -13
- package/dist/components/AppShell/AppShell.module.scss.cjs +22 -10
- package/dist/components/AppShell/AppShell.module.scss.js +22 -10
- package/dist/components/AppShell/index.cjs +1 -1
- package/dist/components/AppShell/index.js +1 -1
- package/dist/components/Avatar/Avatar.module.scss.cjs +13 -13
- package/dist/components/Avatar/Avatar.module.scss.js +13 -13
- package/dist/components/Badge/Badge.module.scss.cjs +16 -16
- package/dist/components/Badge/Badge.module.scss.js +16 -16
- package/dist/components/BentoGrid/BentoGrid.module.scss.cjs +14 -14
- package/dist/components/BentoGrid/BentoGrid.module.scss.js +14 -14
- package/dist/components/Box/Box.module.scss.cjs +152 -152
- package/dist/components/Box/Box.module.scss.js +152 -152
- package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.cjs +8 -8
- package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.js +8 -8
- package/dist/components/Button/Button.module.scss.cjs +13 -13
- package/dist/components/Button/Button.module.scss.js +13 -13
- package/dist/components/Card/Card.module.scss.cjs +17 -17
- package/dist/components/Card/Card.module.scss.js +17 -17
- package/dist/components/Card/index.d.ts +3 -3
- package/dist/components/Card/index.d.ts.map +1 -1
- package/dist/components/Chart/Chart.module.scss.cjs +15 -15
- package/dist/components/Chart/Chart.module.scss.js +15 -15
- package/dist/components/Checkbox/Checkbox.module.scss.cjs +11 -11
- package/dist/components/Checkbox/Checkbox.module.scss.js +11 -11
- package/dist/components/Chip/Chip.module.scss.cjs +15 -15
- package/dist/components/Chip/Chip.module.scss.js +15 -15
- package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +21 -21
- package/dist/components/CodeBlock/CodeBlock.module.scss.js +21 -21
- package/dist/components/Collapsible/Collapsible.module.scss.cjs +10 -10
- package/dist/components/Collapsible/Collapsible.module.scss.js +10 -10
- package/dist/components/ColorPicker/ColorPicker.module.scss.cjs +14 -14
- package/dist/components/ColorPicker/ColorPicker.module.scss.js +14 -14
- package/dist/components/Combobox/Combobox.module.scss.cjs +23 -23
- package/dist/components/Combobox/Combobox.module.scss.js +23 -23
- package/dist/components/Command/Command.module.scss.cjs +11 -11
- package/dist/components/Command/Command.module.scss.js +11 -11
- package/dist/components/ConversationList/ConversationList.module.scss.cjs +10 -10
- package/dist/components/ConversationList/ConversationList.module.scss.js +10 -10
- package/dist/components/DataTable/DataTable.module.scss.cjs +34 -34
- package/dist/components/DataTable/DataTable.module.scss.js +34 -34
- package/dist/components/DataTable/index.d.ts +3 -1
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DatePicker/DatePicker.module.scss.cjs +33 -33
- package/dist/components/DatePicker/DatePicker.module.scss.js +33 -33
- package/dist/components/DatePicker/index.d.ts +1 -1
- package/dist/components/DatePicker/index.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.module.scss.cjs +14 -14
- package/dist/components/Dialog/Dialog.module.scss.js +14 -14
- package/dist/components/Drawer/Drawer.module.scss.cjs +28 -28
- package/dist/components/Drawer/Drawer.module.scss.js +28 -28
- package/dist/components/Drawer/index.cjs +20 -3
- package/dist/components/Drawer/index.d.ts.map +1 -1
- package/dist/components/Drawer/index.js +20 -3
- package/dist/components/Editor/Editor.module.scss.cjs +17 -17
- package/dist/components/Editor/Editor.module.scss.js +17 -17
- package/dist/components/EmptyState/EmptyState.module.scss.cjs +8 -8
- package/dist/components/EmptyState/EmptyState.module.scss.js +8 -8
- package/dist/components/Field/Field.module.scss.cjs +4 -4
- package/dist/components/Field/Field.module.scss.js +4 -4
- package/dist/components/Field/index.cjs +10 -9
- package/dist/components/Field/index.d.ts +7 -7
- package/dist/components/Field/index.d.ts.map +1 -1
- package/dist/components/Field/index.js +10 -9
- package/dist/components/Fieldset/Fieldset.module.scss.cjs +3 -3
- package/dist/components/Fieldset/Fieldset.module.scss.js +3 -3
- package/dist/components/Header/Header.module.scss.cjs +44 -29
- package/dist/components/Header/Header.module.scss.js +44 -29
- package/dist/components/Header/index.cjs +56 -3
- package/dist/components/Header/index.d.ts +25 -3
- package/dist/components/Header/index.d.ts.map +1 -1
- package/dist/components/Header/index.js +56 -3
- package/dist/components/Icon/Icon.module.scss.cjs +8 -8
- package/dist/components/Icon/Icon.module.scss.js +8 -8
- package/dist/components/IconButton/IconButton.module.scss.cjs +8 -8
- package/dist/components/IconButton/IconButton.module.scss.js +8 -8
- package/dist/components/Image/Image.module.scss.cjs +27 -27
- package/dist/components/Image/Image.module.scss.js +27 -27
- package/dist/components/Input/Input.module.scss.cjs +19 -19
- package/dist/components/Input/Input.module.scss.js +19 -19
- package/dist/components/Link/Link.module.scss.cjs +10 -10
- package/dist/components/Link/Link.module.scss.js +10 -10
- package/dist/components/List/List.module.scss.cjs +19 -19
- package/dist/components/List/List.module.scss.js +19 -19
- package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
- package/dist/components/Listbox/Listbox.module.scss.js +8 -8
- package/dist/components/Loading/Loading.module.scss.cjs +30 -30
- package/dist/components/Loading/Loading.module.scss.js +30 -30
- package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
- package/dist/components/Markdown/Markdown.module.scss.js +1 -1
- package/dist/components/Menu/Menu.module.scss.cjs +14 -14
- package/dist/components/Menu/Menu.module.scss.js +14 -14
- package/dist/components/Message/Message.module.scss.cjs +18 -18
- package/dist/components/Message/Message.module.scss.js +18 -18
- package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +28 -28
- package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +28 -28
- package/dist/components/Pagination/Pagination.module.scss.cjs +7 -7
- package/dist/components/Pagination/Pagination.module.scss.js +7 -7
- package/dist/components/Popover/Popover.module.scss.cjs +10 -10
- package/dist/components/Popover/Popover.module.scss.js +10 -10
- package/dist/components/Popover/index.cjs +27 -2
- package/dist/components/Popover/index.d.ts.map +1 -1
- package/dist/components/Popover/index.js +27 -2
- package/dist/components/Progress/Progress.module.scss.cjs +25 -25
- package/dist/components/Progress/Progress.module.scss.js +25 -25
- package/dist/components/Prompt/Prompt.module.scss.cjs +18 -18
- package/dist/components/Prompt/Prompt.module.scss.js +18 -18
- package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +17 -17
- package/dist/components/RadioGroup/RadioGroup.module.scss.js +17 -17
- package/dist/components/RadioGroup/index.cjs +2 -0
- package/dist/components/RadioGroup/index.d.ts +2 -0
- package/dist/components/RadioGroup/index.d.ts.map +1 -1
- package/dist/components/RadioGroup/index.js +2 -0
- package/dist/components/ScrollArea/ScrollArea.module.scss.cjs +10 -10
- package/dist/components/ScrollArea/ScrollArea.module.scss.js +10 -10
- package/dist/components/Select/Select.module.scss.cjs +17 -17
- package/dist/components/Select/Select.module.scss.js +17 -17
- package/dist/components/Separator/Separator.module.scss.cjs +10 -10
- package/dist/components/Separator/Separator.module.scss.js +10 -10
- package/dist/components/Sidebar/Sidebar.module.scss.cjs +42 -42
- package/dist/components/Sidebar/Sidebar.module.scss.js +42 -42
- package/dist/components/Skeleton/Skeleton.module.scss.cjs +38 -38
- package/dist/components/Skeleton/Skeleton.module.scss.js +38 -38
- package/dist/components/Slider/Slider.module.scss.cjs +12 -12
- package/dist/components/Slider/Slider.module.scss.js +12 -12
- package/dist/components/Table/Table.module.scss.cjs +18 -18
- package/dist/components/Table/Table.module.scss.js +18 -18
- package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +15 -15
- package/dist/components/TableOfContents/TableOfContents.module.scss.js +15 -15
- package/dist/components/Tabs/Tabs.module.scss.cjs +12 -12
- package/dist/components/Tabs/Tabs.module.scss.js +12 -12
- package/dist/components/Text/Text.module.scss.cjs +51 -51
- package/dist/components/Text/Text.module.scss.js +51 -51
- package/dist/components/Textarea/Textarea.module.scss.cjs +23 -23
- package/dist/components/Textarea/Textarea.module.scss.js +23 -23
- package/dist/components/Theme/ThemeToggle.module.scss.cjs +6 -6
- package/dist/components/Theme/ThemeToggle.module.scss.js +6 -6
- package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.cjs +13 -13
- package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.js +13 -13
- package/dist/components/Toast/Toast.module.scss.cjs +21 -21
- package/dist/components/Toast/Toast.module.scss.js +21 -21
- package/dist/components/Toggle/Toggle.module.scss.cjs +13 -13
- package/dist/components/Toggle/Toggle.module.scss.js +13 -13
- package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
- package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
- package/dist/components/Tooltip/Tooltip.module.scss.cjs +3 -3
- package/dist/components/Tooltip/Tooltip.module.scss.js +3 -3
- package/dist/data-table.cjs +58 -41
- package/dist/data-table.js +59 -41
- package/dist/datepicker.cjs +32 -72
- package/dist/datepicker.js +32 -72
- package/dist/index.cjs +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/fragments.json +1 -1
- package/package.json +4 -8
- package/src/assets/fragments-wordmark.tsx +47 -0
- package/src/components/Accordion/index.tsx +13 -3
- package/src/components/Alert/Alert.module.scss +15 -2
- package/src/components/AppShell/AppShell.module.scss +73 -15
- package/src/components/AppShell/index.tsx +1 -1
- package/src/components/Button/Button.module.scss +19 -20
- package/src/components/Card/Card.module.scss +3 -3
- package/src/components/Card/index.tsx +3 -3
- package/src/components/CodeBlock/CodeBlock.module.scss +2 -7
- package/src/components/Combobox/Combobox.module.scss +3 -2
- package/src/components/DataTable/DataTable.contract.json +16 -23
- package/src/components/DataTable/index.tsx +25 -4
- package/src/components/DatePicker/index.tsx +32 -84
- package/src/components/Drawer/index.tsx +38 -12
- package/src/components/Field/index.tsx +35 -35
- package/src/components/Header/Header.contract.json +41 -1
- package/src/components/Header/Header.module.scss +40 -0
- package/src/components/Header/index.tsx +88 -2
- package/src/components/IconButton/IconButton.contract.json +120 -0
- package/src/components/Listbox/Listbox.module.scss +5 -4
- package/src/components/Menu/Menu.module.scss +8 -10
- package/src/components/Popover/index.tsx +34 -2
- package/src/components/RadioGroup/RadioGroup.contract.json +13 -27
- package/src/components/RadioGroup/index.tsx +4 -0
- package/src/components/Select/Select.module.scss +13 -12
- package/src/components/TableOfContents/TableOfContents.module.scss +10 -1
- package/src/components/Toast/Toast.module.scss +15 -2
- package/src/components/ToggleGroup/ToggleGroup.module.scss +4 -1
- package/src/index.ts +1 -0
- package/src/styles/globals.scss +13 -10
- package/src/tokens/_component-properties.scss +25 -0
- package/src/tokens/_computed.scss +22 -4
- package/src/tokens/_derive.scss +55 -6
- package/src/tokens/_palettes.scss +24 -0
- package/src/tokens/_seeds.scss +20 -12
- package/src/tokens/_variables.scss +110 -63
|
@@ -25,12 +25,26 @@ export type HeaderIconSlot =
|
|
|
25
25
|
|
|
26
26
|
export type HeaderIcons = Partial<Record<HeaderIconRenderState['slot'], HeaderIconSlot>>;
|
|
27
27
|
|
|
28
|
+
export type HeaderNavAlign = 'start' | 'center';
|
|
29
|
+
export type HeaderContainer = 'full' | 'page';
|
|
30
|
+
|
|
31
|
+
export interface HeaderElevatedOnScrollOptions {
|
|
32
|
+
/** Scroll offset before the elevated surface is applied */
|
|
33
|
+
threshold?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
export interface HeaderProps extends React.HTMLAttributes<HTMLElement> {
|
|
29
37
|
children: React.ReactNode;
|
|
30
38
|
/** Header height (default: '56px') */
|
|
31
39
|
height?: string;
|
|
32
40
|
/** Position behavior */
|
|
33
41
|
position?: 'static' | 'fixed' | 'sticky';
|
|
42
|
+
/** Apply the elevated header surface after scroll */
|
|
43
|
+
elevatedOnScroll?: boolean | HeaderElevatedOnScrollOptions;
|
|
44
|
+
/** Navigation alignment inside the header */
|
|
45
|
+
navAlign?: HeaderNavAlign;
|
|
46
|
+
/** Header content width */
|
|
47
|
+
container?: HeaderContainer;
|
|
34
48
|
/** Optional icon overrides for internal header controls (mobile trigger + nav menu chevron) */
|
|
35
49
|
icons?: HeaderIcons;
|
|
36
50
|
}
|
|
@@ -39,6 +53,8 @@ export interface HeaderBrandProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
39
53
|
children: React.ReactNode;
|
|
40
54
|
/** Link destination */
|
|
41
55
|
href?: string;
|
|
56
|
+
/** Render as child element (polymorphic) */
|
|
57
|
+
asChild?: boolean;
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
export interface HeaderNavProps extends React.HTMLAttributes<HTMLElement> {
|
|
@@ -101,6 +117,10 @@ export interface HeaderMobileNavProps {
|
|
|
101
117
|
className?: string;
|
|
102
118
|
}
|
|
103
119
|
|
|
120
|
+
export interface HeaderMobileNavActionsProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
121
|
+
children: React.ReactNode;
|
|
122
|
+
}
|
|
123
|
+
|
|
104
124
|
// ============================================
|
|
105
125
|
// Internal Context
|
|
106
126
|
// ============================================
|
|
@@ -175,17 +195,37 @@ function HeaderRoot({
|
|
|
175
195
|
children,
|
|
176
196
|
height = '56px',
|
|
177
197
|
position = 'static',
|
|
198
|
+
elevatedOnScroll = false,
|
|
199
|
+
navAlign = 'start',
|
|
200
|
+
container = 'full',
|
|
178
201
|
icons,
|
|
179
202
|
className,
|
|
180
203
|
style: styleProp,
|
|
181
204
|
...htmlProps
|
|
182
205
|
}: HeaderProps) {
|
|
183
206
|
const [mobileOpen, setMobileOpen] = React.useState(false);
|
|
207
|
+
const [scrolled, setScrolled] = React.useState(false);
|
|
208
|
+
const shouldElevateOnScroll = Boolean(elevatedOnScroll);
|
|
209
|
+
const scrollThreshold =
|
|
210
|
+
typeof elevatedOnScroll === 'object' ? (elevatedOnScroll.threshold ?? 16) : 16;
|
|
211
|
+
|
|
212
|
+
React.useEffect(() => {
|
|
213
|
+
if (!shouldElevateOnScroll) return;
|
|
214
|
+
|
|
215
|
+
const updateScrolled = () => setScrolled(window.scrollY > scrollThreshold);
|
|
216
|
+
updateScrolled();
|
|
217
|
+
window.addEventListener('scroll', updateScrolled, { passive: true });
|
|
218
|
+
return () => window.removeEventListener('scroll', updateScrolled);
|
|
219
|
+
}, [scrollThreshold, shouldElevateOnScroll]);
|
|
184
220
|
|
|
185
221
|
const classes = [
|
|
186
222
|
styles.header,
|
|
187
223
|
position === 'fixed' && styles.fixed,
|
|
188
224
|
position === 'sticky' && styles.sticky,
|
|
225
|
+
shouldElevateOnScroll && styles.elevatedOnScroll,
|
|
226
|
+
shouldElevateOnScroll && scrolled && styles.scrolled,
|
|
227
|
+
navAlign === 'center' && styles.navCentered,
|
|
228
|
+
container === 'page' && styles.containerPage,
|
|
189
229
|
className,
|
|
190
230
|
].filter(Boolean).join(' ');
|
|
191
231
|
|
|
@@ -202,7 +242,13 @@ function HeaderRoot({
|
|
|
202
242
|
return (
|
|
203
243
|
<HeaderContext.Provider value={contextValue}>
|
|
204
244
|
<HeaderIconContext.Provider value={icons}>
|
|
205
|
-
<header
|
|
245
|
+
<header
|
|
246
|
+
{...htmlProps}
|
|
247
|
+
className={classes}
|
|
248
|
+
style={style}
|
|
249
|
+
data-position={position}
|
|
250
|
+
data-scrolled={shouldElevateOnScroll ? scrolled : undefined}
|
|
251
|
+
>
|
|
206
252
|
<div className={styles.container}>
|
|
207
253
|
{children}
|
|
208
254
|
</div>
|
|
@@ -215,9 +261,30 @@ function HeaderRoot({
|
|
|
215
261
|
/**
|
|
216
262
|
* Header.Brand - Logo/brand slot
|
|
217
263
|
*/
|
|
218
|
-
function HeaderBrand({
|
|
264
|
+
function HeaderBrand({
|
|
265
|
+
children,
|
|
266
|
+
href,
|
|
267
|
+
asChild = false,
|
|
268
|
+
className,
|
|
269
|
+
...htmlProps
|
|
270
|
+
}: HeaderBrandProps) {
|
|
219
271
|
const classes = [styles.brand, className].filter(Boolean).join(' ');
|
|
220
272
|
|
|
273
|
+
if (asChild && React.isValidElement(children)) {
|
|
274
|
+
const childProps = children.props as {
|
|
275
|
+
className?: string;
|
|
276
|
+
onClick?: React.MouseEventHandler<HTMLElement>;
|
|
277
|
+
};
|
|
278
|
+
const { onClick, ...restHtmlProps } = htmlProps as React.HTMLAttributes<HTMLElement>;
|
|
279
|
+
|
|
280
|
+
return React.cloneElement(children, {
|
|
281
|
+
...restHtmlProps,
|
|
282
|
+
...(href ? { href } : {}),
|
|
283
|
+
className: [classes, childProps.className].filter(Boolean).join(' '),
|
|
284
|
+
onClick: onClick ? composeEventHandlers(childProps.onClick, onClick) : childProps.onClick,
|
|
285
|
+
} as React.HTMLAttributes<HTMLElement>);
|
|
286
|
+
}
|
|
287
|
+
|
|
221
288
|
if (href) {
|
|
222
289
|
return (
|
|
223
290
|
<a {...htmlProps} href={href} className={classes}>
|
|
@@ -604,6 +671,23 @@ function HeaderMobileNavLink({
|
|
|
604
671
|
);
|
|
605
672
|
}
|
|
606
673
|
|
|
674
|
+
/**
|
|
675
|
+
* Header.MobileNavActions - Action row inside the mobile drawer
|
|
676
|
+
*/
|
|
677
|
+
function HeaderMobileNavActions({
|
|
678
|
+
children,
|
|
679
|
+
className,
|
|
680
|
+
...htmlProps
|
|
681
|
+
}: HeaderMobileNavActionsProps) {
|
|
682
|
+
const classes = [styles.mobileNavActions, className].filter(Boolean).join(' ');
|
|
683
|
+
|
|
684
|
+
return (
|
|
685
|
+
<div {...htmlProps} className={classes}>
|
|
686
|
+
{children}
|
|
687
|
+
</div>
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
|
|
607
691
|
/**
|
|
608
692
|
* Header.SkipLink - Skip to main content link (accessibility)
|
|
609
693
|
*/
|
|
@@ -641,6 +725,7 @@ export const Header = Object.assign(HeaderRoot, {
|
|
|
641
725
|
SkipLink: HeaderSkipLink,
|
|
642
726
|
MobileNav: HeaderMobileNav,
|
|
643
727
|
MobileNavLink: HeaderMobileNavLink,
|
|
728
|
+
MobileNavActions: HeaderMobileNavActions,
|
|
644
729
|
});
|
|
645
730
|
|
|
646
731
|
export {
|
|
@@ -657,4 +742,5 @@ export {
|
|
|
657
742
|
HeaderSkipLink,
|
|
658
743
|
HeaderMobileNav,
|
|
659
744
|
HeaderMobileNavLink,
|
|
745
|
+
HeaderMobileNavActions,
|
|
660
746
|
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://usefragments.com/schemas/contract.v1.json",
|
|
3
|
+
"name": "IconButton",
|
|
4
|
+
"description": "Compact square button for icon-only actions in dense toolbars, top bars, and row controls.",
|
|
5
|
+
"category": "forms",
|
|
6
|
+
"tags": ["action", "button", "icon", "toolbar", "interactive"],
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"sourcePath": "src/components/IconButton/index.tsx",
|
|
9
|
+
"exportName": "IconButton",
|
|
10
|
+
"propsSummary": [
|
|
11
|
+
"children: node (required)",
|
|
12
|
+
"variant: ghost|subtle|outlined (default: ghost)",
|
|
13
|
+
"size: sm|md|lg (default: md)",
|
|
14
|
+
"pressed: boolean",
|
|
15
|
+
"aria-label: string",
|
|
16
|
+
"aria-labelledby: string"
|
|
17
|
+
],
|
|
18
|
+
"props": {
|
|
19
|
+
"children": {
|
|
20
|
+
"type": "node",
|
|
21
|
+
"description": "Icon element rendered inside the button",
|
|
22
|
+
"required": true
|
|
23
|
+
},
|
|
24
|
+
"variant": {
|
|
25
|
+
"type": "enum",
|
|
26
|
+
"description": "Visual treatment for the icon-only action",
|
|
27
|
+
"default": "ghost",
|
|
28
|
+
"required": false,
|
|
29
|
+
"values": ["ghost", "subtle", "outlined"]
|
|
30
|
+
},
|
|
31
|
+
"size": {
|
|
32
|
+
"type": "enum",
|
|
33
|
+
"description": "Control size aligned with adjacent fields and toolbar actions",
|
|
34
|
+
"default": "md",
|
|
35
|
+
"required": false,
|
|
36
|
+
"values": ["sm", "md", "lg"]
|
|
37
|
+
},
|
|
38
|
+
"pressed": {
|
|
39
|
+
"type": "boolean",
|
|
40
|
+
"description": "Marks a toggle-style action as pressed and sets aria-pressed",
|
|
41
|
+
"required": false
|
|
42
|
+
},
|
|
43
|
+
"aria-label": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"description": "Accessible action name when no labelled-by relationship is available",
|
|
46
|
+
"required": false
|
|
47
|
+
},
|
|
48
|
+
"aria-labelledby": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"description": "ID reference for an external accessible action label",
|
|
51
|
+
"required": false
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"usage": {
|
|
55
|
+
"when": [
|
|
56
|
+
"Compact icon-only actions in toolbars or top bars",
|
|
57
|
+
"Row actions where a text button would be too wide",
|
|
58
|
+
"Toggle-style icon actions with a visible pressed state"
|
|
59
|
+
],
|
|
60
|
+
"whenNot": [
|
|
61
|
+
"The action needs a visible text label (use Button)",
|
|
62
|
+
"The control changes a persistent boolean setting (use Switch)",
|
|
63
|
+
"The icon is decorative and not interactive (use Icon)"
|
|
64
|
+
],
|
|
65
|
+
"guidelines": [
|
|
66
|
+
"Always provide aria-label or aria-labelledby",
|
|
67
|
+
"Use ghost for ordinary toolbar actions and outlined when more separation is needed",
|
|
68
|
+
"Use pressed only when the button represents a persistent toggle state"
|
|
69
|
+
],
|
|
70
|
+
"accessibility": [
|
|
71
|
+
"Every icon-only button must have an accessible name",
|
|
72
|
+
"The accessible name should describe the action, not the icon",
|
|
73
|
+
"Pressed state must be exposed with aria-pressed"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"examples": [
|
|
77
|
+
{
|
|
78
|
+
"name": "Toolbar action",
|
|
79
|
+
"description": "A named icon-only toolbar action",
|
|
80
|
+
"code": "<IconButton aria-label=\"Add item\">\n <PlusIcon aria-hidden />\n</IconButton>"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "Pressed state",
|
|
84
|
+
"description": "A toggle-style action with its state exposed",
|
|
85
|
+
"code": "import { PushPin as PinIcon } from '@phosphor-icons/react';\n\n<IconButton aria-label=\"Pin item\" pressed>\n <PinIcon aria-hidden />\n</IconButton>"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"relations": [
|
|
89
|
+
{
|
|
90
|
+
"component": "Button",
|
|
91
|
+
"relationship": "sibling",
|
|
92
|
+
"note": "Use Button when the action should have a visible text label or broader layout variants"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"component": "Icon",
|
|
96
|
+
"relationship": "complementary",
|
|
97
|
+
"note": "Icon supplies the visual glyph rendered inside IconButton"
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"contract": {
|
|
101
|
+
"propsSummary": [
|
|
102
|
+
"children: ReactNode - icon element (required)",
|
|
103
|
+
"variant: ghost|subtle|outlined - visual treatment",
|
|
104
|
+
"size: sm|md|lg - square control size",
|
|
105
|
+
"pressed: boolean - toggle state exposed with aria-pressed",
|
|
106
|
+
"aria-label or aria-labelledby - required accessible name"
|
|
107
|
+
],
|
|
108
|
+
"a11yRules": ["A11Y_BTN_LABEL", "A11Y_BTN_FOCUS", "A11Y_TARGET_SIZE_MIN"]
|
|
109
|
+
},
|
|
110
|
+
"ai": {
|
|
111
|
+
"compositionPattern": "compound",
|
|
112
|
+
"subComponents": ["Root"]
|
|
113
|
+
},
|
|
114
|
+
"provenance": {
|
|
115
|
+
"source": "migrated",
|
|
116
|
+
"verified": false,
|
|
117
|
+
"frameworkSupport": "native",
|
|
118
|
+
"extractedAt": "2026-07-14T00:00:00.000Z"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
@use
|
|
2
|
-
@use
|
|
1
|
+
@use "../../tokens/variables" as *;
|
|
2
|
+
@use "../../tokens/mixins" as *;
|
|
3
3
|
|
|
4
4
|
// ============================================
|
|
5
5
|
// Listbox container
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
@include popup-container;
|
|
11
11
|
|
|
12
12
|
// Item height derived from text-base font + vertical padding (matches Select/Combobox)
|
|
13
|
-
--
|
|
13
|
+
--_listbox-item-h: calc(
|
|
14
14
|
var(--fui-font-size-sm, #{$fui-font-size-sm}) *
|
|
15
15
|
var(--fui-line-height-normal, #{$fui-line-height-normal}) +
|
|
16
16
|
var(--fui-space-2, #{$fui-space-2}) * 2
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
min-width: 12rem;
|
|
20
20
|
// Show N items + half-peek scroll hint (default 4.5 items)
|
|
21
21
|
max-height: calc(
|
|
22
|
-
var(--
|
|
22
|
+
var(--_listbox-item-h) * var(--fui-select-max-items, 4.5) +
|
|
23
|
+
var(--fui-space-1, #{$fui-space-1}) * 2
|
|
23
24
|
);
|
|
24
25
|
overflow-y: auto;
|
|
25
26
|
border-color: var(--fui-form-group-border, $fui-border);
|
|
@@ -8,6 +8,7 @@ $fui-arrow-size: 10px !default;
|
|
|
8
8
|
.positioner {
|
|
9
9
|
z-index: 52;
|
|
10
10
|
outline: none;
|
|
11
|
+
pointer-events: auto;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
// Popup container
|
|
@@ -19,23 +20,21 @@ $fui-arrow-size: 10px !default;
|
|
|
19
20
|
margin: 0;
|
|
20
21
|
min-width: 12rem;
|
|
21
22
|
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
// Menus must be fully hit-testable as soon as they open. A fade/scale
|
|
24
|
+
// entrance can let fast clicks pass through to page links under the portal.
|
|
25
|
+
opacity: 1;
|
|
26
|
+
transform: none;
|
|
25
27
|
transform-origin: var(--transform-origin);
|
|
26
|
-
transition:
|
|
27
|
-
opacity var(--fui-transition-fast, $fui-transition-fast),
|
|
28
|
-
transform var(--fui-transition-fast, $fui-transition-fast);
|
|
29
28
|
|
|
30
29
|
&[data-open] {
|
|
31
30
|
opacity: 1;
|
|
32
|
-
transform:
|
|
31
|
+
transform: none;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
&[data-starting-style],
|
|
36
35
|
&[data-ending-style] {
|
|
37
|
-
opacity:
|
|
38
|
-
transform:
|
|
36
|
+
opacity: 1;
|
|
37
|
+
transform: none;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
@@ -204,7 +203,6 @@ $fui-arrow-size: 10px !default;
|
|
|
204
203
|
|
|
205
204
|
@media (prefers-reduced-motion: reduce) {
|
|
206
205
|
.popup {
|
|
207
|
-
transition: none;
|
|
208
206
|
transform: none;
|
|
209
207
|
|
|
210
208
|
&[data-starting-style],
|
|
@@ -110,6 +110,28 @@ function CloseIcon() {
|
|
|
110
110
|
);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// ============================================
|
|
114
|
+
// Helpers
|
|
115
|
+
// ============================================
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Base UI's button-like triggers default `nativeButton` to `true`. When an
|
|
119
|
+
* `asChild` trigger renders something other than a native `<button>` (an
|
|
120
|
+
* anchor, or a component rendered `as="a"`), that default is wrong and Base UI
|
|
121
|
+
* warns that native button semantics were removed. Resolve the correct value
|
|
122
|
+
* from the child so the trigger stays honest and the warning goes away.
|
|
123
|
+
*/
|
|
124
|
+
function resolveNativeButton(child: React.ReactElement): boolean {
|
|
125
|
+
const type = child.type;
|
|
126
|
+
// Intrinsic elements: only `<button>` is a native button.
|
|
127
|
+
if (typeof type === 'string') return type === 'button';
|
|
128
|
+
// Custom components render a native `<button>` by default; treat anchors
|
|
129
|
+
// (via `as="a"` or an `href`) as non-native.
|
|
130
|
+
const props = (child.props ?? {}) as Record<string, unknown>;
|
|
131
|
+
if (props.as === 'a' || props.href != null) return false;
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
113
135
|
// ============================================
|
|
114
136
|
// Components
|
|
115
137
|
// ============================================
|
|
@@ -139,7 +161,12 @@ function PopoverTrigger({ children, asChild, className, ...htmlProps }: PopoverT
|
|
|
139
161
|
throw new Error('Popover.Trigger with asChild requires a single valid React element child.');
|
|
140
162
|
}
|
|
141
163
|
return (
|
|
142
|
-
<BasePopover.Trigger
|
|
164
|
+
<BasePopover.Trigger
|
|
165
|
+
{...htmlProps}
|
|
166
|
+
nativeButton={resolveNativeButton(children as React.ReactElement)}
|
|
167
|
+
className={className}
|
|
168
|
+
render={children as React.ReactElement}
|
|
169
|
+
>
|
|
143
170
|
{null}
|
|
144
171
|
</BasePopover.Trigger>
|
|
145
172
|
);
|
|
@@ -240,7 +267,12 @@ function PopoverClose({ children, asChild, className, ...htmlProps }: PopoverClo
|
|
|
240
267
|
throw new Error('Popover.Close with asChild requires a single valid React element child.');
|
|
241
268
|
}
|
|
242
269
|
return (
|
|
243
|
-
<BasePopover.Close
|
|
270
|
+
<BasePopover.Close
|
|
271
|
+
{...htmlProps}
|
|
272
|
+
nativeButton={resolveNativeButton(children as React.ReactElement)}
|
|
273
|
+
className={className}
|
|
274
|
+
render={children as React.ReactElement}
|
|
275
|
+
>
|
|
244
276
|
{null}
|
|
245
277
|
</BasePopover.Close>
|
|
246
278
|
);
|
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
"name": "RadioGroup",
|
|
4
4
|
"description": "Single selection from a list of mutually exclusive options",
|
|
5
5
|
"category": "forms",
|
|
6
|
-
"tags": [
|
|
7
|
-
"form",
|
|
8
|
-
"radio",
|
|
9
|
-
"selection",
|
|
10
|
-
"options"
|
|
11
|
-
],
|
|
6
|
+
"tags": ["form", "radio", "selection", "options"],
|
|
12
7
|
"status": "stable",
|
|
13
8
|
"sourcePath": "src/components/RadioGroup/index.tsx",
|
|
14
9
|
"exportName": "RadioGroup",
|
|
@@ -26,6 +21,7 @@
|
|
|
26
21
|
"size: sm|md|lg (default: md)",
|
|
27
22
|
"wrapperClassName: string",
|
|
28
23
|
"groupClassName: string",
|
|
24
|
+
"groupId: string",
|
|
29
25
|
"children: node (required)"
|
|
30
26
|
],
|
|
31
27
|
"props": {
|
|
@@ -54,10 +50,7 @@
|
|
|
54
50
|
"description": "Layout orientation",
|
|
55
51
|
"default": "vertical",
|
|
56
52
|
"required": false,
|
|
57
|
-
"values": [
|
|
58
|
-
"horizontal",
|
|
59
|
-
"vertical"
|
|
60
|
-
]
|
|
53
|
+
"values": ["horizontal", "vertical"]
|
|
61
54
|
},
|
|
62
55
|
"disabled": {
|
|
63
56
|
"type": "boolean",
|
|
@@ -90,21 +83,14 @@
|
|
|
90
83
|
"description": "Size variant",
|
|
91
84
|
"default": "md",
|
|
92
85
|
"required": false,
|
|
93
|
-
"values": [
|
|
94
|
-
"sm",
|
|
95
|
-
"md",
|
|
96
|
-
"lg"
|
|
97
|
-
]
|
|
86
|
+
"values": ["sm", "md", "lg"]
|
|
98
87
|
},
|
|
99
88
|
"variant": {
|
|
100
89
|
"type": "enum",
|
|
101
90
|
"description": "Visual variant. 'default' is the inline radio, 'card' renders each item as a full-width clickable card with the radio tucked inside.",
|
|
102
91
|
"default": "default",
|
|
103
92
|
"required": false,
|
|
104
|
-
"values": [
|
|
105
|
-
"default",
|
|
106
|
-
"card"
|
|
107
|
-
]
|
|
93
|
+
"values": ["default", "card"]
|
|
108
94
|
},
|
|
109
95
|
"wrapperClassName": {
|
|
110
96
|
"type": "string",
|
|
@@ -116,6 +102,11 @@
|
|
|
116
102
|
"description": "Class name for the inner radio group element",
|
|
117
103
|
"required": false
|
|
118
104
|
},
|
|
105
|
+
"groupId": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"description": "ID for the inner element with role=radiogroup; the inherited id remains on the outer field wrapper",
|
|
108
|
+
"required": false
|
|
109
|
+
},
|
|
119
110
|
"children": {
|
|
120
111
|
"type": "node",
|
|
121
112
|
"description": "RadioGroup.Item elements",
|
|
@@ -213,19 +204,14 @@
|
|
|
213
204
|
"error: boolean | string - error styling and message",
|
|
214
205
|
"disabled: boolean - disable all options",
|
|
215
206
|
"wrapperClassName/groupClassName - explicit styling targets for wrapper and group",
|
|
207
|
+
"groupId: string - ID forwarded to the inner radiogroup while id remains on the wrapper",
|
|
216
208
|
"RadioGroup.Item supports helperText (preferred) and description (legacy alias) plus controlClassName/contentClassName for item-level styling"
|
|
217
209
|
],
|
|
218
|
-
"a11yRules": [
|
|
219
|
-
"A11Y_RADIO_GROUP",
|
|
220
|
-
"A11Y_LABEL_REQUIRED",
|
|
221
|
-
"A11Y_TARGET_SIZE_MIN"
|
|
222
|
-
]
|
|
210
|
+
"a11yRules": ["A11Y_RADIO_GROUP", "A11Y_LABEL_REQUIRED", "A11Y_TARGET_SIZE_MIN"]
|
|
223
211
|
},
|
|
224
212
|
"ai": {
|
|
225
213
|
"compositionPattern": "compound",
|
|
226
|
-
"subComponents": [
|
|
227
|
-
"Item"
|
|
228
|
-
]
|
|
214
|
+
"subComponents": ["Item"]
|
|
229
215
|
},
|
|
230
216
|
"provenance": {
|
|
231
217
|
"source": "migrated",
|
|
@@ -61,6 +61,8 @@ export interface RadioGroupProps extends Omit<
|
|
|
61
61
|
wrapperClassName?: string;
|
|
62
62
|
/** Class applied to the inner radio group container */
|
|
63
63
|
groupClassName?: string;
|
|
64
|
+
/** ID applied to the inner element with `role="radiogroup"`. The inherited `id` remains on the outer field wrapper for compatibility. */
|
|
65
|
+
groupId?: string;
|
|
64
66
|
/** Children (Radio.Item components) */
|
|
65
67
|
children: React.ReactNode;
|
|
66
68
|
}
|
|
@@ -216,6 +218,7 @@ const RadioGroupRoot = React.forwardRef<HTMLDivElement, RadioGroupProps>(functio
|
|
|
216
218
|
variant = "default",
|
|
217
219
|
wrapperClassName,
|
|
218
220
|
groupClassName,
|
|
221
|
+
groupId,
|
|
219
222
|
children,
|
|
220
223
|
className,
|
|
221
224
|
"aria-label": ariaLabel,
|
|
@@ -252,6 +255,7 @@ const RadioGroupRoot = React.forwardRef<HTMLDivElement, RadioGroupProps>(functio
|
|
|
252
255
|
</span>
|
|
253
256
|
)}
|
|
254
257
|
<BaseRadioGroup
|
|
258
|
+
id={groupId}
|
|
255
259
|
value={value}
|
|
256
260
|
defaultValue={defaultValue}
|
|
257
261
|
onValueChange={handleValueChange}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
@use
|
|
2
|
-
@use
|
|
1
|
+
@use "../../tokens/variables" as *;
|
|
2
|
+
@use "../../tokens/mixins" as *;
|
|
3
3
|
|
|
4
4
|
// Form field wrapper (label + helper + error)
|
|
5
5
|
@include form-field-wrapper;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
@include interactive-base;
|
|
11
11
|
@include text-base;
|
|
12
12
|
@include field-shell;
|
|
13
|
-
@include control-size(
|
|
13
|
+
@include control-size("md", "input");
|
|
14
14
|
|
|
15
15
|
display: inline-flex;
|
|
16
16
|
align-items: center;
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
|
|
28
28
|
// Trigger size variants
|
|
29
29
|
.triggerSm {
|
|
30
|
-
@include control-size(
|
|
30
|
+
@include control-size("sm", "input");
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
.triggerLg {
|
|
34
|
-
@include control-size(
|
|
34
|
+
@include control-size("lg", "input");
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// Value display
|
|
@@ -86,17 +86,18 @@
|
|
|
86
86
|
border-color: var(--fui-form-group-border, $fui-border);
|
|
87
87
|
|
|
88
88
|
// Item height derived from text-base font + vertical padding
|
|
89
|
-
--
|
|
90
|
-
var(--fui-font-size-sm, #{$fui-font-size-sm}) *
|
|
91
|
-
|
|
89
|
+
--_select-item-h: calc(
|
|
90
|
+
var(--fui-font-size-sm, #{$fui-font-size-sm}) *
|
|
91
|
+
var(--fui-line-height-normal, #{$fui-line-height-normal}) +
|
|
92
|
+
var(--fui-space-2, #{$fui-space-2}) * 2
|
|
92
93
|
);
|
|
93
94
|
|
|
94
95
|
min-width: var(--anchor-width);
|
|
95
96
|
// Show N items + half-peek scroll hint (default 4.5 items)
|
|
96
97
|
// !important needed to override Base UI's inline max-height: 100%
|
|
97
98
|
max-height: calc(
|
|
98
|
-
var(--
|
|
99
|
-
|
|
99
|
+
var(--_select-item-h) * var(--fui-select-max-items, 4.5) + var(--fui-space-1, #{$fui-space-1}) *
|
|
100
|
+
2
|
|
100
101
|
) !important;
|
|
101
102
|
overflow-y: auto !important;
|
|
102
103
|
|
|
@@ -214,12 +215,12 @@
|
|
|
214
215
|
background-color: var(--fui-bg-elevated, $fui-bg-elevated);
|
|
215
216
|
border: 1px solid var(--fui-border, $fui-border);
|
|
216
217
|
|
|
217
|
-
&[data-side=
|
|
218
|
+
&[data-side="top"] {
|
|
218
219
|
border-top: none;
|
|
219
220
|
border-left: none;
|
|
220
221
|
}
|
|
221
222
|
|
|
222
|
-
&[data-side=
|
|
223
|
+
&[data-side="bottom"] {
|
|
223
224
|
border-bottom: none;
|
|
224
225
|
border-right: none;
|
|
225
226
|
}
|
|
@@ -176,6 +176,15 @@ $rail-from-item-1: $rail-x-1 - $rail-pad; // 3px
|
|
|
176
176
|
// Item link
|
|
177
177
|
// ============================================
|
|
178
178
|
|
|
179
|
+
// ── Plain index (design-system default) ──────────────────────────────────────
|
|
180
|
+
// The "on this page" index reads as a quiet list — the active row is signalled
|
|
181
|
+
// by ink + medium weight (see .active), not a coloured rail. Drop the per-row
|
|
182
|
+
// rail and elbow pseudo-elements the snake geometry above would otherwise draw.
|
|
183
|
+
.root [data-depth]::before,
|
|
184
|
+
.root [data-depth]::after {
|
|
185
|
+
content: none;
|
|
186
|
+
}
|
|
187
|
+
|
|
179
188
|
.link {
|
|
180
189
|
display: flex;
|
|
181
190
|
align-items: center;
|
|
@@ -231,7 +240,7 @@ $rail-from-item-1: $rail-x-1 - $rail-pad; // 3px
|
|
|
231
240
|
}
|
|
232
241
|
|
|
233
242
|
.active {
|
|
234
|
-
color: var(--fui-
|
|
243
|
+
color: var(--fui-text-primary, $fui-text-primary);
|
|
235
244
|
font-weight: var(--fui-font-weight-medium, $fui-font-weight-medium);
|
|
236
245
|
}
|
|
237
246
|
|
|
@@ -63,7 +63,9 @@
|
|
|
63
63
|
|
|
64
64
|
.toast {
|
|
65
65
|
display: flex;
|
|
66
|
-
|
|
66
|
+
// Single-line toasts (title only) read best vertically centered; toasts
|
|
67
|
+
// with a description are multi-line and top-align — see `:has(.description)`.
|
|
68
|
+
align-items: center;
|
|
67
69
|
gap: var(--fui-space-1, $fui-space-1);
|
|
68
70
|
padding: var(--fui-space-2, $fui-space-2) var(--fui-space-3, $fui-space-3);
|
|
69
71
|
background-color: var(--fui-bg-elevated, $fui-bg-elevated);
|
|
@@ -76,6 +78,12 @@
|
|
|
76
78
|
animation: toastEnter var(--fui-transition-normal, $fui-transition-normal);
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
// With a description the toast is multi-line: top-align icon/close to the
|
|
82
|
+
// first line rather than the block centre.
|
|
83
|
+
.toast:has(.description) {
|
|
84
|
+
align-items: flex-start;
|
|
85
|
+
}
|
|
86
|
+
|
|
79
87
|
@keyframes toastEnter {
|
|
80
88
|
from {
|
|
81
89
|
opacity: 0;
|
|
@@ -177,7 +185,6 @@
|
|
|
177
185
|
flex-shrink: 0;
|
|
178
186
|
width: 1.25rem;
|
|
179
187
|
height: 1.25rem;
|
|
180
|
-
margin-top: 1px;
|
|
181
188
|
|
|
182
189
|
svg {
|
|
183
190
|
width: 100%;
|
|
@@ -185,6 +192,12 @@
|
|
|
185
192
|
}
|
|
186
193
|
}
|
|
187
194
|
|
|
195
|
+
// Nudge the icon to meet the first line only in multi-line toasts; centered
|
|
196
|
+
// single-line toasts need no offset.
|
|
197
|
+
.toast:has(.description) .icon {
|
|
198
|
+
margin-top: 1px;
|
|
199
|
+
}
|
|
200
|
+
|
|
188
201
|
.content {
|
|
189
202
|
flex: 1;
|
|
190
203
|
min-width: 0;
|
|
@@ -37,7 +37,10 @@
|
|
|
37
37
|
.item {
|
|
38
38
|
background-color: transparent;
|
|
39
39
|
border: 1px solid transparent;
|
|
40
|
-
|
|
40
|
+
// Match the container's radius (form-group-surface = --fui-radius-lg),
|
|
41
|
+
// less its 1px inset border, so the selected fill nests inside the
|
|
42
|
+
// container corners instead of poking past them.
|
|
43
|
+
border-radius: calc(var(--fui-radius-lg, #{$fui-radius-lg}) - 1px);
|
|
41
44
|
|
|
42
45
|
&.selected {
|
|
43
46
|
background-color: var(--fui-toggle-group-selected-bg, var(--fui-bg-hover, #{$fui-bg-hover}));
|