Merge pull request #30919 from backstage/bui-tag-group

BUI - Add TagGroup component
This commit is contained in:
Charles de Dreuille
2025-08-18 13:00:43 +01:00
committed by GitHub
18 changed files with 914 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/ui': patch
---
Add new TagGroup component to Backstage UI.
+4
View File
@@ -209,6 +209,10 @@
.bui-Input {
border-radius: var(--bui-radius-3);
}
.bui-Tag {
border-radius: var(--bui-radius-full);
}
}
[data-theme-mode='light'][data-theme-name='spotify'] {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,114 @@
import { PropsTable } from '@/components/PropsTable';
import { Snippet } from '@/components/Snippet';
import { CodeBlock } from '@/components/CodeBlock';
import { TagGroupSnippet } from '@/snippets/stories-snippets';
import {
tagGroupPropDefs,
tagPropDefs,
usage,
preview,
withLink,
disabled,
withIcons,
sizes,
removingTags,
} from './tag-group.props';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
<PageTitle
title="TagGroup"
description="A tag group is a list of labels, categories, keywords, filters, or other items, that can be used to group and filter content."
/>
<Snippet
align="center"
py={4}
preview={<TagGroupSnippet story="Default" />}
code={preview}
/>
## Usage
<CodeBlock code={usage} />
## API reference
### TagGroup
A tag group is a list of tags.
<PropsTable data={tagGroupPropDefs} />
### Tag
A tag is a single item in a tag group.
<PropsTable data={tagPropDefs} />
## Examples
### With Links
A tag can be a link by passing a `href` prop.
<Snippet
align="center"
py={4}
open
preview={<TagGroupSnippet story="WithLink" />}
code={withLink}
/>
### With Icons
A tag can have an icon by passing a `icon` prop.
<Snippet
align="center"
py={4}
open
preview={<TagGroupSnippet story="WithIcon" />}
code={withIcons}
/>
### Sizes
A tag can have a size by passing a `size` prop. It could be `small` or `medium`.
<Snippet
align="center"
py={4}
open
preview={<TagGroupSnippet story="Sizes" />}
code={sizes}
/>
### Removing tags
A tag can be removed by passing a `onRemove` prop.
<Snippet
align="center"
py={4}
open
preview={<TagGroupSnippet story="RemovingTags" />}
code={removingTags}
/>
### Disabled
A switch can be disabled using the `isDisabled` prop.
<Snippet
align="center"
py={4}
open
preview={<TagGroupSnippet story="Disabled" />}
code={disabled}
/>
<Theming component="Switch" />
<ChangelogComponent component="switch" />
@@ -0,0 +1,161 @@
import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs';
import type { PropDef } from '@/utils/propDefs';
export const tagGroupPropDefs: Record<string, PropDef> = {
disabledKeys: {
type: 'enum',
values: ['Iterable<Key>'],
description: 'A list of row keys to disable.',
},
selectionMode: {
type: 'enum',
values: ['none', 'single', 'multiple'],
description: 'The type of selection that is allowed in the collection.',
},
selectedKeys: {
type: 'enum',
values: ['all', 'Iterable<Key>'],
description: 'The currently selected keys in the collection (controlled).',
},
defaultSelectedKeys: {
type: 'enum',
values: ['all', 'Iterable<Key>'],
description: 'The initial selected keys in the collection (uncontrolled).',
},
onRemove: {
type: 'enum',
values: ['(keys: Set<Key>) => void'],
description: 'Handler that is called when a tag is removed.',
},
onSelectionChange: {
type: 'enum',
values: ['(keys: Selection) => void'],
description: 'Handler that is called when the selection changes.',
},
...classNamePropDefs,
...stylePropDefs,
};
export const tagPropDefs: Record<string, PropDef> = {
id: {
type: 'string',
description: 'The id of the tag.',
},
textValue: {
type: 'string',
description: 'The text value of the tag.',
},
isDisabled: {
type: 'boolean',
description: 'Whether the tag is disabled.',
},
href: {
type: 'string',
description: 'The href of the tag.',
},
icon: {
type: 'enum',
values: ['ReactNode'],
description: 'The icon of the tag.',
},
...classNamePropDefs,
...stylePropDefs,
};
export const preview = `import { TagGroup, Tag } from '@backstage/ui';
<TagGroup aria-label="Tag Group">
<Tag>Banana</Tag>
<Tag>Apple</Tag>
<Tag>Orange</Tag>
<Tag>Pear</Tag>
<Tag>Grape</Tag>
<Tag>Pineapple</Tag>
<Tag>Strawberry</Tag>
</TagGroup>
`;
export const usage = `import { TagGroup, Tag } from '@backstage/ui';
// Basic usage
<TagGroup aria-label="Tag Group">
<Tag>Tag 1</Tag>
<Tag>Tag 2</Tag>
<Tag>Tag 3</Tag>
</TagGroup>
// With the items prop
const list = [
{ id: '1', name: 'Tag 1' },
{ id: '2', name: 'Tag 2' },
{ id: '3', name: 'Tag 3' },
];
<TagGroup aria-label="Tag Group" items={list}>
{item => <Tag>{item.name}</Tag>}
</TagGroup>`;
export const withLink = `import { TagGroup, Tag } from '@backstage/ui';
<TagGroup aria-label="Tag Group">
<Tag href="/items/banana">Banana</Tag>
<Tag href="/items/apple">Apple</Tag>
<Tag href="/items/orange">Orange</Tag>
...
</TagGroup>`;
export const disabled = `import { TagGroup, Tag } from '@backstage/ui';
<TagGroup aria-label="Tag Group">
<Tag>Banana</Tag>
<Tag isDisabled>Apple</Tag>
<Tag isDisabled>Orange</Tag>
<Tag>Pear</Tag>
...
</TagGroup>`;
export const withIcons = `import { TagGroup, Tag } from '@backstage/ui';
<TagGroup aria-label="Tag Group">
<Tag icon={<RiBugLine />}>Banana</Tag>
<Tag icon={<RiAccountCircleLine />}>Apple</Tag>
<Tag icon={<RiEyeLine />}>Orange</Tag>
...
</TagGroup>`;
export const sizes = `import { TagGroup, Tag, Flex } from '@backstage/ui';
<Flex direction="column">
<TagGroup aria-label="Tag Group">
<Tag size="small">Banana</Tag>
<Tag size="small">Apple</Tag>
<Tag size="small">Orange</Tag>
...
</TagGroup>
<TagGroup aria-label="Tag Group">
<Tag size="medium">Banana</Tag>
<Tag size="medium">Apple</Tag>
<Tag size="medium">Orange</Tag>
...
</TagGroup>
</Flex>`;
export const removingTags = `import { TagGroup, Tag } from '@backstage/ui';
import type { Selection } from 'react-aria-components';
import { useListData } from 'react-stately';
const [selected, setSelected] = useState<Selection>(new Set(['travel']));
const list = useListData({
initialItems: initialList,
});
<TagGroup
items={list.items}
onRemove={keys => list.remove(...keys)}
selectedKeys={selected}
onSelectionChange={setSelected}
{...args}
>
{item => <Tag>{item.name}</Tag>}
</TagGroup>`;
@@ -27,6 +27,7 @@ import * as CardStories from '../../../packages/ui/src/components/Card/Card.stor
import * as HeaderStories from '../../../packages/ui/src/components/Header/Header.stories';
import * as HeaderPageStories from '../../../packages/ui/src/components/HeaderPage/HeaderPage.stories';
import * as TableStories from '../../../packages/ui/src/components/Table/Table.stories';
import * as TagGroupStories from '../../../packages/ui/src/components/TagGroup/TagGroup.stories';
// Helper function to create snippet components
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -69,3 +70,4 @@ export const CardSnippet = createSnippetComponent(CardStories);
export const HeaderSnippet = createSnippetComponent(HeaderStories);
export const HeaderPageSnippet = createSnippetComponent(HeaderPageStories);
export const TableSnippet = createSnippetComponent(TableStories);
export const TagGroupSnippet = createSnippetComponent(TagGroupStories);
+6 -1
View File
@@ -154,13 +154,18 @@ export const components: Page[] = [
{
title: 'Table',
slug: 'table',
status: 'inProgress',
status: 'alpha',
},
{
title: 'Tabs',
slug: 'tabs',
status: 'alpha',
},
{
title: 'TagGroup',
slug: 'tag-group',
status: 'alpha',
},
{
title: 'Text',
slug: 'text',
+75
View File
@@ -10260,6 +10260,81 @@
padding-top: var(--bui-space-4);
}
.bui-TagList {
gap: var(--bui-space-2);
flex-wrap: wrap;
display: flex;
}
.bui-Tag {
color: var(--bui-fg-primary);
background-color: var(--bui-gray-2);
border-radius: var(--bui-radius-2);
font-weight: var(--bui-font-weight-regular);
justify-content: center;
align-items: center;
gap: var(--bui-space-1);
box-sizing: border-box;
transition-property: background-color, box-shadow, color;
transition-duration: .2s;
transition-timing-function: ease-in-out;
display: flex;
}
.bui-Tag[data-size="small"] {
height: 26px;
padding: 0 var(--bui-space-2);
font-size: var(--bui-font-size-1);
}
.bui-Tag[data-size="medium"] {
height: 32px;
padding: 0 var(--bui-space-2);
font-size: var(--bui-font-size-2);
}
.bui-Tag[data-hovered] {
background-color: var(--bui-gray-3);
cursor: pointer;
}
.bui-Tag[data-focus-visible] {
outline: 2px solid var(--bui-ring);
outline-offset: 1px;
}
.bui-Tag[data-selected] {
box-shadow: inset 0 0 0 1px var(--bui-gray-8);
}
.bui-Tag[data-disabled] {
color: var(--bui-fg-disabled);
cursor: not-allowed;
}
.bui-TagRemoveButton {
cursor: pointer;
color: var(--bui-fg-primary);
background-color: #0000;
border: none;
width: 1rem;
height: 1rem;
margin: 0;
padding: 0;
}
.bui-TagIcon {
justify-content: center;
align-items: center;
transition: color .2s ease-in-out;
display: flex;
& svg {
width: 1rem;
height: 1rem;
}
}
.bui-Text {
font-family: var(--bui-font-regular);
margin: 0;
+34
View File
@@ -42,6 +42,9 @@ import type { TabListProps as TabListProps_2 } from 'react-aria-components';
import type { TabPanelProps as TabPanelProps_2 } from 'react-aria-components';
import type { TabProps as TabProps_2 } from 'react-aria-components';
import { TabsProps as TabsProps_2 } from 'react-aria-components';
import type { TagGroupProps as TagGroupProps_2 } from 'react-aria-components';
import type { TagListProps } from 'react-aria-components';
import type { TagProps as TagProps_2 } from 'react-aria-components';
import type { TextFieldProps as TextFieldProps_2 } from 'react-aria-components';
import { TooltipProps as TooltipProps_2 } from 'react-aria-components';
import { TooltipTriggerComponentProps } from 'react-aria-components';
@@ -608,6 +611,15 @@ export const componentDefinitions: {
readonly panel: 'bui-TabPanel';
};
};
readonly TagGroup: {
readonly classNames: {
readonly group: 'bui-TagGroup';
readonly list: 'bui-TagList';
readonly tag: 'bui-Tag';
readonly tagIcon: 'bui-TagIcon';
readonly tagRemoveButton: 'bui-TagRemoveButton';
};
};
readonly Text: {
readonly classNames: {
readonly root: 'bui-Text';
@@ -1697,6 +1709,28 @@ export const Tabs: (props: TabsProps) => JSX_2.Element | null;
// @public
export interface TabsProps extends TabsProps_2 {}
// @public
export const Tag: (props: TagProps) => JSX_2.Element;
// @public
export const TagGroup: <T extends object>({
items,
children,
renderEmptyState,
...props
}: TagGroupProps<T>) => JSX_2.Element;
// @public
export interface TagGroupProps<T>
extends Omit<TagGroupProps_2, 'children'>,
Pick<TagListProps<T>, 'items' | 'children' | 'renderEmptyState'> {}
// @public
export interface TagProps extends TagProps_2 {
icon?: React.ReactNode;
size?: 'small' | 'medium';
}
// @public (undocumented)
const Text_2: {
<T extends ElementType = 'p'>(
@@ -0,0 +1,241 @@
/*
* 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';
import { TagGroup, Tag } from '.';
import type { Selection } from 'react-aria-components';
import { Flex, Icon, IconNames } from '../../';
import { useListData } from 'react-stately';
import { MemoryRouter } from 'react-router-dom';
export interface ListItem {
id: string;
name: string;
icon: IconNames;
isDisabled?: boolean;
}
const meta = {
title: 'Backstage UI/TagGroup',
component: TagGroup<ListItem>,
argTypes: {
selectionMode: {
control: { type: 'inline-radio' },
options: ['single', 'multiple'],
},
'aria-label': {
control: { type: 'text' },
},
},
decorators: [
Story => (
<MemoryRouter>
<Story />
</MemoryRouter>
),
],
} satisfies Meta<typeof TagGroup<ListItem>>;
export default meta;
type Story = StoryObj<typeof meta>;
const initialList: ListItem[] = [
{ id: 'banana', name: 'Banana', icon: 'bug' },
{ id: 'apple', name: 'Apple', icon: 'account-circle', isDisabled: true },
{ id: 'orange', name: 'Orange', icon: 'eye', isDisabled: true },
{ id: 'pear', name: 'Pear', icon: 'heart' },
{ id: 'grape', name: 'Grape', icon: 'bug' },
{ id: 'pineapple', name: 'Pineapple', icon: 'eye' },
{ id: 'strawberry', name: 'Strawberry', icon: 'heart' },
];
export const Default: Story = {
args: {
'aria-label': 'Tag Group',
},
render: args => (
<TagGroup {...args}>
{initialList.map(item => (
<Tag key={item.id}>{item.name}</Tag>
))}
</TagGroup>
),
};
export const Sizes: Story = {
args: {
...Default.args,
},
render: args => (
<Flex direction="column">
<TagGroup {...args}>
{initialList.map(item => (
<Tag key={item.id} size="small" icon={<Icon name={item.icon} />}>
{item.name}
</Tag>
))}
</TagGroup>
<TagGroup {...args}>
{initialList.map(item => (
<Tag key={item.id} size="medium" icon={<Icon name={item.icon} />}>
{item.name}
</Tag>
))}
</TagGroup>
</Flex>
),
};
export const SelectionModeSingle: Story = {
args: {
selectionMode: 'single',
'aria-label': 'Tag Group',
},
render: args => {
const [selected, setSelected] = useState<Selection>(new Set(['travel']));
return (
<TagGroup
items={initialList}
selectedKeys={selected}
onSelectionChange={setSelected}
{...args}
>
{item => <Tag>{item.name}</Tag>}
</TagGroup>
);
},
};
export const SelectionModeMultiple: Story = {
args: {
selectionMode: 'multiple',
'aria-label': 'Tag Group',
},
render: args => {
const [selected, setSelected] = useState<Selection>(
new Set(['travel', 'shopping']),
);
return (
<TagGroup
items={initialList}
selectedKeys={selected}
onSelectionChange={setSelected}
{...args}
>
{item => <Tag>{item.name}</Tag>}
</TagGroup>
);
},
};
export const WithIcon: Story = {
args: {
...Default.args,
},
render: args => (
<TagGroup {...args}>
{initialList.map(item => (
<Tag
key={item.id}
icon={item.icon ? <Icon name={item.icon} /> : undefined}
>
{item.name}
</Tag>
))}
</TagGroup>
),
};
export const WithLink: Story = {
render: args => (
<TagGroup {...args}>
{initialList.map(item => (
<Tag key={item.id} href={`/items/${item.id}`}>
{item.name}
</Tag>
))}
</TagGroup>
),
};
export const Disabled: Story = {
render: args => (
<TagGroup {...args}>
{initialList.map(item => (
<Tag key={item.id} isDisabled={item.isDisabled}>
{item.name}
</Tag>
))}
</TagGroup>
),
};
export const RemovingTags: Story = {
args: {
...Default.args,
},
render: args => {
const [selected, setSelected] = useState<Selection>(new Set(['travel']));
const list = useListData({
initialItems: initialList,
});
return (
<TagGroup
items={list.items}
onRemove={keys => list.remove(...keys)}
selectedKeys={selected}
onSelectionChange={setSelected}
{...args}
>
{item => <Tag>{item.name}</Tag>}
</TagGroup>
);
},
};
export const WithIconAndRemoveButton: Story = {
args: {
...Default.args,
},
render: args => {
const [selected, setSelected] = useState<Selection>(new Set(['travel']));
const list = useListData({
initialItems: initialList,
});
return (
<TagGroup
items={list.items}
onRemove={keys => list.remove(...keys)}
selectedKeys={selected}
onSelectionChange={setSelected}
{...args}
>
{item => (
<Tag icon={item.icon ? <Icon name={item.icon} /> : undefined}>
{item.name}
</Tag>
)}
</TagGroup>
);
},
};
@@ -0,0 +1,90 @@
/*
* 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.
*/
.bui-TagList {
display: flex;
flex-wrap: wrap;
gap: var(--bui-space-2);
}
.bui-Tag {
color: var(--bui-fg-primary);
background-color: var(--bui-gray-2);
border-radius: var(--bui-radius-2);
display: flex;
align-items: center;
justify-content: center;
font-weight: var(--bui-font-weight-regular);
gap: var(--bui-space-1);
transition-property: background-color, box-shadow, color;
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
box-sizing: border-box;
}
.bui-Tag[data-size='small'] {
height: 26px;
padding: 0 var(--bui-space-2);
font-size: var(--bui-font-size-1);
}
.bui-Tag[data-size='medium'] {
height: 32px;
padding: 0 var(--bui-space-2);
font-size: var(--bui-font-size-2);
}
.bui-Tag[data-hovered] {
background-color: var(--bui-gray-3);
cursor: pointer;
}
.bui-Tag[data-focus-visible] {
outline: 2px solid var(--bui-ring);
outline-offset: 1px;
}
.bui-Tag[data-selected] {
box-shadow: inset 0 0 0 1px var(--bui-gray-8);
}
.bui-Tag[data-disabled] {
color: var(--bui-fg-disabled);
cursor: not-allowed;
}
.bui-TagRemoveButton {
background-color: transparent;
border: none;
cursor: pointer;
color: var(--bui-fg-primary);
padding: 0;
margin: 0;
width: 1rem;
height: 1rem;
}
.bui-TagIcon {
display: flex;
align-items: center;
justify-content: center;
transition: color 0.2s ease-in-out;
svg {
width: 1rem;
height: 1rem;
}
}
@@ -0,0 +1,104 @@
/*
* 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 type { TagProps, TagGroupProps } from './types';
import {
TagGroup as ReactAriaTagGroup,
TagList as ReactAriaTagList,
Tag as ReactAriaTag,
Button as ReactAriaButton,
RouterProvider,
} from 'react-aria-components';
import type { ReactNode } from 'react';
import { RiCloseCircleLine } from '@remixicon/react';
import clsx from 'clsx';
import { useStyles } from '../../hooks/useStyles';
import { isExternalLink } from '../../utils/isExternalLink';
import { useNavigate, useHref } from 'react-router-dom';
/**
* A component that renders a list of tags.
*
* @public
*/
export const TagGroup = <T extends object>({
items,
children,
renderEmptyState,
...props
}: TagGroupProps<T>) => {
const { classNames } = useStyles('TagGroup');
return (
<ReactAriaTagGroup className={classNames.group} {...props}>
<ReactAriaTagList
className={classNames.list}
items={items}
renderEmptyState={renderEmptyState}
>
{children}
</ReactAriaTagList>
</ReactAriaTagGroup>
);
};
/**
* A component that renders a tag.
*
* @public
*/
export const Tag = (props: TagProps) => {
const { children, className, icon, size = 'small', href, ...rest } = props;
const textValue = typeof children === 'string' ? children : undefined;
const { classNames } = useStyles('TagGroup');
const navigate = useNavigate();
const isLink = href !== undefined;
const isExternal = isExternalLink(href);
const content = (
<ReactAriaTag
textValue={textValue}
className={clsx(classNames.tag, className)}
data-size={size}
href={href}
{...rest}
>
{({ allowsRemoving }) => (
<>
{icon && <span className={classNames.tagIcon}>{icon}</span>}
{children as ReactNode}
{allowsRemoving && (
<ReactAriaButton
className={classNames.tagRemoveButton}
slot="remove"
>
<RiCloseCircleLine size={16} />
</ReactAriaButton>
)}
</>
)}
</ReactAriaTag>
);
if (isLink && !isExternal) {
return (
<RouterProvider navigate={navigate} useHref={useHref}>
{content}
</RouterProvider>
);
}
return content;
};
@@ -0,0 +1,18 @@
/*
* 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.
*/
export { TagGroup, Tag } from './TagGroup';
export type { TagGroupProps, TagProps } from './types';
@@ -0,0 +1,47 @@
/*
* 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 type {
TagGroupProps as ReactAriaTagGroupProps,
TagListProps as ReactAriaTagListProps,
TagProps as ReactAriaTagProps,
} from 'react-aria-components';
/**
* Props for the TagGroup component.
*
* @public
*/
export interface TagGroupProps<T>
extends Omit<ReactAriaTagGroupProps, 'children'>,
Pick<ReactAriaTagListProps<T>, 'items' | 'children' | 'renderEmptyState'> {}
/**
* Props for the Tag component.
*
* @public
*/
export interface TagProps extends ReactAriaTagProps {
/**
* The icon to display in the chip.
*/
icon?: React.ReactNode;
/**
* The size of the chip.
*/
size?: 'small' | 'medium';
}
+1
View File
@@ -36,6 +36,7 @@
@import '../components/Table/Table.styles.css';
@import '../components/TablePagination/TablePagination.styles.css';
@import '../components/Tabs/Tabs.styles.css';
@import '../components/TagGroup/TagGroup.styles.css';
@import '../components/Text/styles.css';
@import '../components/TextField/TextField.styles.css';
@import '../components/SearchField/SearchField.styles.css';
+1
View File
@@ -45,6 +45,7 @@ export * from './components/RadioGroup';
export * from './components/Table';
export * from './components/TablePagination';
export * from './components/Tabs';
export * from './components/TagGroup';
export * from './components/Text';
export * from './components/TextField';
export * from './components/Tooltip';
@@ -260,6 +260,15 @@ export const componentDefinitions = {
panel: 'bui-TabPanel',
},
},
TagGroup: {
classNames: {
group: 'bui-TagGroup',
list: 'bui-TagList',
tag: 'bui-Tag',
tagIcon: 'bui-TagIcon',
tagRemoveButton: 'bui-TagRemoveButton',
},
},
Text: {
classNames: {
root: 'bui-Text',