Improve BUI manifest

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2026-03-30 11:02:31 +01:00
parent 0336f92de8
commit dc009ed8a9
42 changed files with 274 additions and 288 deletions
+2 -2
View File
@@ -63,13 +63,13 @@
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/use-sync-external-store": "^0.0.6",
"eslint-plugin-storybook": "^10.3.0-alpha.1",
"eslint-plugin-storybook": "^10.3.3",
"glob": "^11.0.1",
"globals": "^17.0.0",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-router-dom": "^6.30.2",
"storybook": "^10.3.0-alpha.1"
"storybook": "^10.3.3"
},
"peerDependencies": {
"@types/react": "^18.0.0",
@@ -38,7 +38,11 @@ import {
} from './definition';
import { Flex } from '../Flex';
/** @public */
/**
* A collapsible section that reveals or hides its content when the trigger is activated.
*
* @public
*/
export const Accordion = forwardRef(
(props: AccordionProps, ref: Ref<React.ElementRef<typeof RADisclosure>>) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
@@ -62,7 +66,11 @@ export const Accordion = forwardRef(
Accordion.displayName = 'Accordion';
/** @public */
/**
* The clickable heading that toggles the visibility of an accordion panel.
*
* @public
*/
export const AccordionTrigger = forwardRef(
(
props: AccordionTriggerProps,
@@ -100,7 +108,11 @@ export const AccordionTrigger = forwardRef(
AccordionTrigger.displayName = 'AccordionTrigger';
/** @public */
/**
* The content area of an accordion that is revealed when the trigger is activated.
*
* @public
*/
export const AccordionPanel = forwardRef(
(
props: AccordionPanelProps,
@@ -125,7 +137,11 @@ export const AccordionPanel = forwardRef(
AccordionPanel.displayName = 'AccordionPanel';
/** @public */
/**
* A container that groups multiple Accordion items, optionally allowing several panels to be expanded at once.
*
* @public
*/
export const AccordionGroup = forwardRef(
(
props: AccordionGroupProps,
+5 -1
View File
@@ -19,7 +19,11 @@ import { AvatarProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { AvatarDefinition } from './definition';
/** @public */
/**
* Displays a user's profile image with an automatic fallback to their initials when the image fails to load.
*
* @public
*/
export const Avatar = forwardRef<HTMLDivElement, AvatarProps>((props, ref) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
AvatarDefinition,
+5 -1
View File
@@ -19,7 +19,11 @@ import { BoxProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { BoxDefinition } from './definition';
/** @public */
/**
* A general-purpose layout primitive that can render as any HTML element and supports spacing, sizing, and background props.
*
* @public
*/
export const Box = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
const { ownProps, restProps, dataAttributes, utilityStyle } = useDefinition(
BoxDefinition,
@@ -21,7 +21,11 @@ import type { ButtonIconProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { ButtonIconDefinition } from './definition';
/** @public */
/**
* An icon-only button that supports a loading state and requires an accessible label.
*
* @public
*/
export const ButtonIcon = forwardRef(
(props: ButtonIconProps, ref: Ref<HTMLButtonElement>) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
@@ -21,7 +21,11 @@ import { useDefinition } from '../../hooks/useDefinition';
import { ButtonLinkDefinition } from './definition';
import { getNodeText } from '../../analytics/getNodeText';
/** @public */
/**
* A button-styled anchor element for navigation, supporting optional start and end icon slots and analytics event tracking.
*
* @public
*/
export const ButtonLink = forwardRef(
(props: ButtonLinkProps, ref: Ref<HTMLAnchorElement>) => {
const { ownProps, restProps, dataAttributes, analytics } = useDefinition(
@@ -21,7 +21,11 @@ import { useDefinition } from '../../hooks/useDefinition';
import { CheckboxDefinition } from './definition';
import { RiCheckLine, RiSubtractLine } from '@remixicon/react';
/** @public */
/**
* A form checkbox input with support for indeterminate state and accessible labeling.
*
* @public
*/
export const Checkbox = forwardRef<HTMLLabelElement, CheckboxProps>(
(props, ref) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
@@ -19,7 +19,11 @@ import type { ContainerProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { ContainerDefinition } from './definition';
/** @public */
/**
* A centered layout wrapper that constrains content to a maximum width and provides consistent page-level padding.
*
* @public
*/
export const Container = forwardRef<HTMLDivElement, ContainerProps>(
(props, ref) => {
const { ownProps, restProps, utilityStyle } = useDefinition(
+25 -5
View File
@@ -41,12 +41,20 @@ import { Box } from '../Box';
import { BgReset } from '../../hooks/useBg';
import { Flex } from '../Flex';
/** @public */
/**
* A wrapper that connects a trigger element to a Dialog, controlling its open and close state.
*
* @public
*/
export const DialogTrigger = (props: DialogTriggerProps) => {
return <RADialogTrigger {...props} />;
};
/** @public */
/**
* A modal overlay that presents content requiring user interaction or acknowledgment, dismissible by clicking outside or pressing Escape.
*
* @public
*/
export const Dialog = forwardRef<React.ElementRef<typeof Modal>, DialogProps>(
(props, ref) => {
const { ownProps, restProps } = useDefinition(DialogDefinition, props, {
@@ -89,7 +97,11 @@ export const Dialog = forwardRef<React.ElementRef<typeof Modal>, DialogProps>(
Dialog.displayName = 'Dialog';
/** @public */
/**
* The header section of a Dialog, containing the title and a close button.
*
* @public
*/
export const DialogHeader = forwardRef<
React.ElementRef<'div'>,
DialogHeaderProps
@@ -110,7 +122,11 @@ export const DialogHeader = forwardRef<
});
DialogHeader.displayName = 'DialogHeader';
/** @public */
/**
* The main scrollable content area of a Dialog.
*
* @public
*/
export const DialogBody = forwardRef<React.ElementRef<'div'>, DialogBodyProps>(
(props, ref) => {
const { ownProps, restProps } = useDefinition(DialogBodyDefinition, props);
@@ -126,7 +142,11 @@ export const DialogBody = forwardRef<React.ElementRef<'div'>, DialogBodyProps>(
DialogBody.displayName = 'DialogBody';
/** @public */
/**
* The footer section of a Dialog, typically used to place action buttons.
*
* @public
*/
export const DialogFooter = forwardRef<
React.ElementRef<'div'>,
DialogFooterProps
@@ -20,7 +20,11 @@ import type { FieldErrorProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { FieldErrorDefinition } from './definition';
/** @public */
/**
* Displays a validation error message associated with a form field.
*
* @public
*/
export const FieldError = forwardRef<HTMLDivElement, FieldErrorProps>(
(props: FieldErrorProps, ref) => {
const { ownProps, restProps } = useDefinition(FieldErrorDefinition, props);
@@ -19,7 +19,11 @@ import type { FieldLabelProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { FieldLabelDefinition } from './definition';
/** @public */
/**
* Renders a label for a form field with optional secondary label and description text.
*
* @public
*/
export const FieldLabel = forwardRef<HTMLDivElement, FieldLabelProps>(
(props: FieldLabelProps, ref) => {
const { ownProps, restProps } = useDefinition(FieldLabelDefinition, props);
+5 -1
View File
@@ -19,7 +19,11 @@ import type { FlexProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { FlexDefinition } from './definition';
/** @public */
/**
* A flexbox layout container with props for controlling gap, alignment, justification, and direction.
*
* @public
*/
export const Flex = forwardRef<HTMLDivElement, FlexProps>((props, ref) => {
const { ownProps, dataAttributes, utilityStyle, restProps } = useDefinition(
FlexDefinition,
+5 -1
View File
@@ -61,7 +61,11 @@ const LinkInternal = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
LinkInternal.displayName = 'LinkInternal';
/** @public */
/**
* A styled anchor element that supports analytics event tracking on click.
*
* @public
*/
export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
return <LinkInternal {...props} ref={ref} />;
});
+5 -1
View File
@@ -76,7 +76,11 @@ const MenuEmptyState = () => {
return <div className={ownProps.classes.root}>No results found.</div>;
};
/** @public */
/**
* A wrapper that connects a trigger element to a dropdown menu, controlling its open and close state.
*
* @public
*/
export const MenuTrigger = (props: MenuTriggerProps) => {
return <RAMenuTrigger {...props} />;
};
@@ -28,7 +28,11 @@ import { useDefinition } from '../../hooks/useDefinition';
import { PasswordFieldDefinition } from './definition';
import { RiEyeLine, RiEyeOffLine } from '@remixicon/react';
/** @public */
/**
* A text input for password entry with a toggleable visibility button, integrated label, and inline error display.
*
* @public
*/
export const PasswordField = forwardRef<HTMLDivElement, PasswordFieldProps>(
(props, ref) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
@@ -26,7 +26,11 @@ import { RadioGroupDefinition, RadioDefinition } from './definition';
import type { RadioGroupProps, RadioProps } from './types';
/** @public */
/**
* A group of radio buttons for selecting a single option from a set, with an integrated label, description, and error display.
*
* @public
*/
export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
(props, ref) => {
const { ownProps, restProps } = useDefinition(RadioGroupDefinition, props);
@@ -70,7 +74,11 @@ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
RadioGroup.displayName = 'RadioGroup';
/** @public */
/**
* A single radio button for use within a RadioGroup.
*
* @public
*/
export const Radio = forwardRef<HTMLLabelElement, RadioProps>((props, ref) => {
const { ownProps, restProps } = useDefinition(RadioDefinition, props);
@@ -47,7 +47,11 @@ const SearchAutocompleteEmptyState = () => {
return <div className={ownProps.classes.emptyState}>No results found.</div>;
};
/** @public */
/**
* A search input that shows a dropdown list of suggestions as the user types, with loading and empty states.
*
* @public
*/
export function SearchAutocomplete(props: SearchAutocompleteProps) {
const { ownProps, dataAttributes } = useDefinition(
SearchAutocompleteDefinition,
@@ -184,7 +188,11 @@ export function SearchAutocomplete(props: SearchAutocompleteProps) {
);
}
/** @public */
/**
* An individual option item within a SearchAutocomplete dropdown.
*
* @public
*/
export function SearchAutocompleteItem(props: SearchAutocompleteItemProps) {
const { ownProps, restProps } = useDefinition(
SearchAutocompleteItemDefinition,
@@ -28,7 +28,11 @@ import { SearchFieldDefinition } from './definition';
import type { SearchFieldProps } from './types';
/** @public */
/**
* A text input optimized for search queries, with a built-in clear button, optional icon, and support for a collapsible mode.
*
* @public
*/
export const SearchField = forwardRef<HTMLDivElement, SearchFieldProps>(
(props, ref) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
+5 -1
View File
@@ -26,7 +26,11 @@ import { FieldError } from '../FieldError';
import { SelectTrigger } from './SelectTrigger';
import { SelectContent } from './SelectContent';
/** @public */
/**
* A dropdown picker for selecting one or multiple options from a list, with optional search filtering and inline error display.
*
* @public
*/
export const Select = forwardRef<
HTMLDivElement,
SelectProps<'single' | 'multiple'>
@@ -18,7 +18,11 @@ import type { SkeletonProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { SkeletonDefinition } from './definition';
/** @public */
/**
* A placeholder shape displayed while content is loading, matching the size and layout of the content it replaces.
*
* @public
*/
export const Skeleton = (props: SkeletonProps) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
SkeletonDefinition,
+5 -1
View File
@@ -115,7 +115,11 @@ function SliderImpl<T extends number | number[]>(
);
}
/** @public */
/**
* A draggable input for selecting a numeric value or range within a defined interval, with an integrated label and value output.
*
* @public
*/
export const Slider = forwardRef(SliderImpl) as (<T extends number | number[]>(
props: SliderProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> },
) => JSX.Element) & { displayName: string };
+5 -1
View File
@@ -20,7 +20,11 @@ import type { SwitchProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { SwitchDefinition } from './definition';
/** @public */
/**
* A toggle control for switching between on and off states, with an optional visible label.
*
* @public
*/
export const Switch = forwardRef<HTMLLabelElement, SwitchProps>(
(props, ref) => {
const { ownProps, restProps } = useDefinition(SwitchDefinition, props);
@@ -19,7 +19,12 @@ import type { CellProps } from '../types';
import { useDefinition } from '../../../hooks/useDefinition';
import { CellDefinition } from '../definition';
/** @public */
/**
* A low-level table cell primitive for building custom cell content.
* For standard use cases, prefer `CellText` or `CellProfile`.
*
* @public
*/
const Cell = (props: CellProps) => {
const { ownProps, restProps } = useDefinition(CellDefinition, props);
@@ -22,7 +22,11 @@ import { useDefinition } from '../../../hooks/useDefinition';
import { CellProfileDefinition } from '../definition';
import { Cell as ReactAriaCell } from 'react-aria-components';
/** @public */
/**
* A table cell that renders an avatar image alongside a name, with an optional description and link.
*
* @public
*/
export const CellProfile = (props: CellProfileProps) => {
const { ownProps, restProps } = useDefinition(CellProfileDefinition, props);
const { classes, src, name, href, description, color } = ownProps;
@@ -21,7 +21,11 @@ import type { CellTextProps } from '../types';
import { useDefinition } from '../../../hooks/useDefinition';
import { CellTextDefinition } from '../definition';
/** @public */
/**
* A table cell that renders a primary text title with an optional secondary description, leading icon, and link.
*
* @public
*/
const CellText = (props: CellTextProps) => {
const { ownProps, restProps } = useDefinition(CellTextDefinition, props);
const { classes, title, description, color, leadingIcon, href } = ownProps;
@@ -20,7 +20,11 @@ import { ColumnDefinition } from '../definition';
import { ColumnProps } from '../types';
import { RiArrowUpLine } from '@remixicon/react';
/** @public */
/**
* A table column header cell with an optional sort toggle and support for resizable widths.
*
* @public
*/
export const Column = (props: ColumnProps) => {
const { ownProps, restProps } = useDefinition(ColumnDefinition, props);
const { classes, children } = ownProps;
@@ -28,7 +28,11 @@ import { isExternalLink } from '../../../utils/linkUtils';
import clsx from 'clsx';
import { Flex } from '../../Flex';
/** @public */
/**
* A table row that can optionally act as a navigation link or trigger an action when clicked, with analytics tracking.
*
* @public
*/
export function Row<T extends object>(props: RowProps<T>) {
const { ownProps, restProps, dataAttributes, analytics } = useDefinition(
RowDefinition,
@@ -98,7 +98,12 @@ function useLiveRegionLabel(
return liveRegionLabel;
}
/** @public */
/**
* A full-featured data table with built-in pagination, sorting, row selection, loading and error states, and optional virtualization.
* Pair with `useTable` to manage data fetching and state, or pass `data` and `pagination` directly for manual control.
*
* @public
*/
export function Table<T extends TableItem>({
columnConfig,
data,
@@ -19,7 +19,11 @@ import { useDefinition } from '../../../hooks/useDefinition';
import { TableBodyDefinition } from '../definition';
import type { TableBodyProps } from '../types';
/** @public */
/**
* The body section of a table that renders data rows from the provided items collection.
*
* @public
*/
export const TableBody = <T extends object>(props: TableBodyProps<T>) => {
const { ownProps, restProps } = useDefinition(TableBodyDefinition, props);
@@ -26,7 +26,11 @@ import { TableHeaderDefinition } from '../definition';
import type { TableHeaderProps } from '../types';
import { Flex } from '../../Flex';
/** @public */
/**
* The header row of a table, rendering column labels and an optional select-all checkbox for toggle selection mode.
*
* @public
*/
export const TableHeader = <T extends object>(props: TableHeaderProps<T>) => {
let { selectionBehavior, selectionMode } = useTableOptions();
@@ -19,7 +19,12 @@ import { TableDefinition } from '../definition';
import { Table as ReactAriaTable } from 'react-aria-components';
import { TableRootProps } from '../types';
/** @public */
/**
* The low-level table root element for building custom table layouts from atomic components.
* For most use cases, prefer the `Table` convenience wrapper.
*
* @public
*/
export const TableRoot = (props: TableRootProps) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
TableDefinition,
@@ -121,7 +121,12 @@ function useTableProps<T extends TableItem>(
);
}
/** @public */
/**
* A hook that manages table data fetching, pagination, sorting, search, and filtering.
* Supports three modes: `complete` for client-side data, `offset` for server-side offset pagination, and `cursor` for server-side cursor pagination.
*
* @public
*/
export function useTable<T extends TableItem, TFilter = unknown>(
options: UseTableCompleteOptions<T, TFilter>,
): UseTableResult<T, TFilter>;
@@ -1,202 +0,0 @@
/* eslint-disable no-restricted-syntax */
/*
* Copyright 2025 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { Table, CellText, CellProfile, useTable, type ColumnConfig } from '..';
import { Flex } from '../../Flex';
import { Text } from '../../Text';
import { RadioGroup, Radio } from '../../RadioGroup';
import { data as data4 } from './mocked-data4';
import { selectionData, selectionColumns, tableStoriesMeta } from './utils';
const meta = {
title: 'Backstage UI/Table/docs',
...tableStoriesMeta,
} satisfies Meta;
export default meta;
type Story = StoryObj<typeof meta>;
type Data4Item = (typeof data4)[0];
export const TableRockBand: Story = {
render: () => {
const columns: ColumnConfig<Data4Item>[] = [
{
id: 'name',
label: 'Band name',
isRowHeader: true,
defaultWidth: '4fr',
cell: item => (
<CellProfile name={item.name} src={item.image} href={item.website} />
),
},
{
id: 'genre',
label: 'Genre',
defaultWidth: '4fr',
cell: item => <CellText title={item.genre} />,
},
{
id: 'yearFormed',
label: 'Year formed',
defaultWidth: '1fr',
cell: item => <CellText title={item.yearFormed.toString()} />,
},
{
id: 'albums',
label: 'Albums',
defaultWidth: '1fr',
cell: item => <CellText title={item.albums.toString()} />,
},
];
const { tableProps } = useTable({
mode: 'complete',
getData: () => data4,
paginationOptions: { pageSize: 5 },
});
return <Table columnConfig={columns} {...tableProps} />;
},
};
export const SelectionToggleWithActions: Story = {
render: () => {
const [selected, setSelected] = useState<Set<string | number> | 'all'>(
new Set(),
);
const { tableProps } = useTable({
mode: 'complete',
getData: () => selectionData,
paginationOptions: { pageSize: 10 },
});
return (
<Table
{...tableProps}
columnConfig={selectionColumns}
selection={{
mode: 'multiple',
behavior: 'toggle',
selected,
onSelectionChange: setSelected,
}}
rowConfig={{ onClick: item => alert(`Clicked: ${item.name}`) }}
/>
);
},
};
export const SelectionModePlayground: Story = {
render: () => {
const [selectionMode, setSelectionMode] = useState<'single' | 'multiple'>(
'multiple',
);
const [selected, setSelected] = useState<Set<string | number> | 'all'>(
new Set(),
);
const { tableProps } = useTable({
mode: 'complete',
getData: () => selectionData,
paginationOptions: { pageSize: 10 },
});
return (
<Flex direction="column" gap="8">
<Table
{...tableProps}
columnConfig={selectionColumns}
selection={{
mode: selectionMode,
behavior: 'toggle',
selected,
onSelectionChange: setSelected,
}}
/>
<div>
<Text as="h4" style={{ marginBottom: 'var(--bui-space-2)' }}>
Selection mode:
</Text>
<RadioGroup
aria-label="Selection mode"
orientation="horizontal"
value={selectionMode}
onChange={value => {
setSelectionMode(value as 'single' | 'multiple');
setSelected(new Set());
}}
>
<Radio value="single">single</Radio>
<Radio value="multiple">multiple</Radio>
</RadioGroup>
</div>
</Flex>
);
},
};
export const SelectionBehaviorPlayground: Story = {
render: () => {
const [selectionBehavior, setSelectionBehavior] = useState<
'toggle' | 'replace'
>('toggle');
const [selected, setSelected] = useState<Set<string | number> | 'all'>(
new Set(),
);
const { tableProps } = useTable({
mode: 'complete',
getData: () => selectionData,
paginationOptions: { pageSize: 10 },
});
return (
<Flex direction="column" gap="8">
<Table
{...tableProps}
columnConfig={selectionColumns}
selection={{
mode: 'multiple',
behavior: selectionBehavior,
selected,
onSelectionChange: setSelected,
}}
/>
<div>
<Text as="h4" style={{ marginBottom: 'var(--bui-space-2)' }}>
Selection behavior:
</Text>
<RadioGroup
aria-label="Selection behavior"
orientation="horizontal"
value={selectionBehavior}
onChange={value => {
setSelectionBehavior(value as 'toggle' | 'replace');
setSelected(new Set());
}}
>
<Radio value="toggle">toggle</Radio>
<Radio value="replace">replace</Radio>
</RadioGroup>
</div>
</Flex>
);
},
};
+5 -1
View File
@@ -47,7 +47,11 @@ function TextComponent<T extends ElementType = 'span'>(
TextComponent.displayName = 'Text';
/** @public */
/**
* A typographic primitive that renders text with design system variants, weights, and colors, and can render as any HTML element.
*
* @public
*/
export const Text = forwardRef(TextComponent) as {
<T extends ElementType = 'p'>(
props: TextProps<T> & { ref?: React.ComponentPropsWithRef<T>['ref'] },
@@ -22,7 +22,11 @@ import type { TextFieldProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { TextFieldDefinition } from './definition';
/** @public */
/**
* A single-line text input with an integrated label, optional icon, and inline error display.
*
* @public
*/
export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
(props, ref) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
@@ -20,7 +20,11 @@ import type { ToggleButtonProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { ToggleButtonDefinition } from './definition';
/** @public */
/**
* A button that maintains a pressed or unpressed state, with optional start and end icon slots.
*
* @public
*/
export const ToggleButton = forwardRef(
(props: ToggleButtonProps, ref: Ref<HTMLButtonElement>) => {
const { ownProps, restProps, dataAttributes } = useDefinition(
@@ -20,7 +20,11 @@ import type { ToggleButtonGroupProps } from './types';
import { useDefinition } from '../../hooks/useDefinition';
import { ToggleButtonGroupDefinition } from './definition';
/** @public */
/**
* A container that groups ToggleButton items and manages their collective selection state.
*
* @public
*/
export const ToggleButtonGroup = forwardRef(
(props: ToggleButtonGroupProps, ref: Ref<HTMLDivElement>) => {
const { ownProps, restProps } = useDefinition(
+10 -2
View File
@@ -28,14 +28,22 @@ import { TooltipDefinition } from './definition';
import { Box } from '../Box';
import { BgReset } from '../../hooks/useBg';
/** @public */
/**
* A wrapper that connects a trigger element to a Tooltip, controlling its show and hide behavior with a configurable delay.
*
* @public
*/
export const TooltipTrigger = (props: TooltipTriggerComponentProps) => {
const { delay = 600 } = props;
return <AriaTooltipTrigger delay={delay} {...props} />;
};
/** @public */
/**
* A floating label that provides contextual information about an element when it receives hover or focus.
*
* @public
*/
export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
(props, ref) => {
const { ownProps, restProps } = useDefinition(TooltipDefinition, props);
+1
View File
@@ -20,6 +20,7 @@ import { Text } from '../components/Text';
const meta = preview.meta({
title: 'Backstage UI/Colors',
tags: ['!manifest'],
});
export const Default = meta.story({