From 36b1ac8802c535d77308fac6a36314b53d60fe78 Mon Sep 17 00:00:00 2001 From: Johan Persson Date: Fri, 27 Feb 2026 11:03:36 +0100 Subject: [PATCH] Migrate TagGroup component from useStyles to useDefinition Split shared TagGroupDefinition into TagGroupDefinition (root) and TagDefinition (tag sub-component). Tag's size prop now uses dataAttribute with default in propDefs instead of manual data-size and default spreading. Signed-off-by: Johan Persson --- packages/ui/report.api.md | 40 ++++++-- .../ui/src/components/TagGroup/TagGroup.tsx | 95 ++++++++----------- .../ui/src/components/TagGroup/definition.ts | 37 ++++++-- packages/ui/src/components/TagGroup/index.ts | 7 +- packages/ui/src/components/TagGroup/types.ts | 49 +++++++--- 5 files changed, 141 insertions(+), 87 deletions(-) diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md index cb92b605d4..75f00f7211 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -2434,25 +2434,47 @@ export const TagGroup: ( // @public export const TagGroupDefinition: { + readonly styles: { + readonly [key: string]: string; + }; readonly classNames: { - readonly group: 'bui-TagGroup'; + readonly root: 'bui-TagGroup'; readonly list: 'bui-TagList'; - readonly tag: 'bui-Tag'; - readonly tagIcon: 'bui-TagIcon'; - readonly tagRemoveButton: 'bui-TagRemoveButton'; + }; + readonly propDefs: { + readonly items: {}; + readonly children: {}; + readonly renderEmptyState: {}; + readonly className: {}; }; }; // @public -export interface TagGroupProps - extends Omit, - Pick, 'items' | 'children' | 'renderEmptyState'> {} +export type TagGroupOwnProps = { + items?: TagListProps['items']; + children?: TagListProps['children']; + renderEmptyState?: TagListProps['renderEmptyState']; + className?: string; +}; // @public -export interface TagProps extends TagProps_2 { +export interface TagGroupProps + extends TagGroupOwnProps, + Omit {} + +// @public +export type TagOwnProps = { icon?: React.ReactNode; size?: 'small' | 'medium'; -} + href?: TagProps_2['href']; + children?: TagProps_2['children']; + className?: string; +}; + +// @public +export interface TagProps + extends TagOwnProps, + Omit {} // @public (undocumented) const Text_2: { diff --git a/packages/ui/src/components/TagGroup/TagGroup.tsx b/packages/ui/src/components/TagGroup/TagGroup.tsx index 66ef46bb72..5208647bd8 100644 --- a/packages/ui/src/components/TagGroup/TagGroup.tsx +++ b/packages/ui/src/components/TagGroup/TagGroup.tsx @@ -21,13 +21,11 @@ import { Tag as ReactAriaTag, Button as ReactAriaButton, } from 'react-aria-components'; -import { forwardRef, type PropsWithRef, type ReactNode, type Ref } from 'react'; +import { forwardRef, type ReactNode } from 'react'; import { RiCloseCircleLine } from '@remixicon/react'; -import clsx from 'clsx'; -import { useStyles } from '../../hooks/useStyles'; -import { TagGroupDefinition } from './definition'; +import { useDefinition } from '../../hooks/useDefinition'; +import { TagGroupDefinition, TagDefinition } from './definition'; import { createRoutingRegistration } from '../InternalLinkProvider'; -import styles from './TagGroup.module.css'; const { RoutingProvider, useRoutingRegistrationEffect } = createRoutingRegistration(); @@ -38,17 +36,14 @@ const { RoutingProvider, useRoutingRegistrationEffect } = * @public */ export const TagGroup = (props: TagGroupProps) => { - const { classNames, cleanedProps } = useStyles(TagGroupDefinition, props); - const { items, children, renderEmptyState, ...rest } = cleanedProps; + const { ownProps, restProps } = useDefinition(TagGroupDefinition, props); + const { classes, items, children, renderEmptyState } = ownProps; return ( - + @@ -64,50 +59,36 @@ export const TagGroup = (props: TagGroupProps) => { * * @public */ -export const Tag = forwardRef( - (props: PropsWithRef, ref: Ref) => { - const { classNames, cleanedProps } = useStyles(TagGroupDefinition, { - size: 'small', - ...props, - }); - const { children, className, icon, size, href, ...rest } = cleanedProps; - const textValue = typeof children === 'string' ? children : undefined; +export const Tag = forwardRef((props, ref) => { + const { ownProps, restProps, dataAttributes } = useDefinition( + TagDefinition, + props, + ); + const { classes, children, icon, href } = ownProps; + const textValue = typeof children === 'string' ? children : undefined; - useRoutingRegistrationEffect(href); + useRoutingRegistrationEffect(href); - return ( - - {({ allowsRemoving }) => ( - <> - {icon && ( - - {icon} - - )} - {children as ReactNode} - {allowsRemoving && ( - - - - )} - - )} - - ); - }, -); + return ( + + {({ allowsRemoving }) => ( + <> + {icon && {icon}} + {children as ReactNode} + {allowsRemoving && ( + + + + )} + + )} + + ); +}); diff --git a/packages/ui/src/components/TagGroup/definition.ts b/packages/ui/src/components/TagGroup/definition.ts index 8ad3d17805..a4134645be 100644 --- a/packages/ui/src/components/TagGroup/definition.ts +++ b/packages/ui/src/components/TagGroup/definition.ts @@ -14,18 +14,41 @@ * limitations under the License. */ -import type { ComponentDefinition } from '../../types'; +import { defineComponent } from '../../hooks/useDefinition'; +import type { TagGroupOwnProps, TagOwnProps } from './types'; +import styles from './TagGroup.module.css'; /** * Component definition for TagGroup * @public */ -export const TagGroupDefinition = { +export const TagGroupDefinition = defineComponent()({ + styles, classNames: { - group: 'bui-TagGroup', + root: 'bui-TagGroup', list: 'bui-TagList', - tag: 'bui-Tag', - tagIcon: 'bui-TagIcon', - tagRemoveButton: 'bui-TagRemoveButton', }, -} as const satisfies ComponentDefinition; + propDefs: { + items: {}, + children: {}, + renderEmptyState: {}, + className: {}, + }, +}); + +/** @internal */ +export const TagDefinition = defineComponent()({ + styles, + classNames: { + root: 'bui-Tag', + icon: 'bui-TagIcon', + removeButton: 'bui-TagRemoveButton', + }, + propDefs: { + icon: {}, + size: { dataAttribute: true, default: 'small' }, + href: {}, + children: {}, + className: {}, + }, +}); diff --git a/packages/ui/src/components/TagGroup/index.ts b/packages/ui/src/components/TagGroup/index.ts index 7c58cf69fc..529470753d 100644 --- a/packages/ui/src/components/TagGroup/index.ts +++ b/packages/ui/src/components/TagGroup/index.ts @@ -15,5 +15,10 @@ */ export { TagGroup, Tag } from './TagGroup'; -export type { TagGroupProps, TagProps } from './types'; +export type { + TagGroupProps, + TagGroupOwnProps, + TagProps, + TagOwnProps, +} from './types'; export { TagGroupDefinition } from './definition'; diff --git a/packages/ui/src/components/TagGroup/types.ts b/packages/ui/src/components/TagGroup/types.ts index e828e6e524..daf146673d 100644 --- a/packages/ui/src/components/TagGroup/types.ts +++ b/packages/ui/src/components/TagGroup/types.ts @@ -20,28 +20,51 @@ import type { TagProps as ReactAriaTagProps, } from 'react-aria-components'; +/** + * Own props for the TagGroup component. + * + * @public + */ +export type TagGroupOwnProps = { + items?: ReactAriaTagListProps['items']; + children?: ReactAriaTagListProps['children']; + renderEmptyState?: ReactAriaTagListProps['renderEmptyState']; + className?: string; +}; + /** * Props for the TagGroup component. * * @public */ export interface TagGroupProps - extends Omit, - Pick, 'items' | 'children' | 'renderEmptyState'> {} + extends TagGroupOwnProps, + Omit {} + +/** + * Own props for the Tag component. + * + * @public + */ +export type TagOwnProps = { + /** + * The icon to display in the chip. + */ + icon?: React.ReactNode; + /** + * The size of the chip. + */ + size?: 'small' | 'medium'; + href?: ReactAriaTagProps['href']; + children?: ReactAriaTagProps['children']; + className?: string; +}; /** * 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'; -} +export interface TagProps + extends TagOwnProps, + Omit {}