diff --git a/apps/website/screens/components/chip/code/ChipCodePage.tsx b/apps/website/screens/components/chip/code/ChipCodePage.tsx index 9f25f914f..dc3560b82 100644 --- a/apps/website/screens/components/chip/code/ChipCodePage.tsx +++ b/apps/website/screens/components/chip/code/ChipCodePage.tsx @@ -1,10 +1,31 @@ -import { DxcFlex, DxcLink, DxcTable } from "@dxc-technology/halstack-react"; +import { DxcFlex, DxcLink, DxcParagraph, DxcTable } from "@dxc-technology/halstack-react"; import QuickNavContainer from "@/common/QuickNavContainer"; import DocFooter from "@/common/DocFooter"; import Example from "@/common/example/Example"; import basicUsage from "./examples/basicUsage"; import icons from "./examples/icons"; -import Code, { TableCode } from "@/common/Code"; +import Code, { ExtendedTableCode, TableCode } from "@/common/Code"; +import StatusBadge from "@/common/StatusBadge"; +import avatar from "./examples/avatar"; + +const actionTypeString = `{ + icon?: string | (React.ReactNode + & React.SVGProps); + onClick: () => void; + title?: string; +}`; + +const prefixTypeString = ` +| string +| SVG +| { + color: 'primary' | 'secondary' | 'tertiary' + | 'success' | 'info' | 'neutral' | 'warning' + | 'error'; + icon?: string | SVG; + imgSrc?: string; + label?: string; + }`; const sections = [ { @@ -20,6 +41,19 @@ const sections = [ + + + + + action + + + + {actionTypeString} + + Action to be displayed on the right side of the chip after the label. + - + disabled @@ -31,7 +65,12 @@ const sections = [ - label + + + + label + + string @@ -50,54 +89,27 @@ const sections = [ - - onClickPrefix - - {"() => void"} - - If defined, the prefix icon will be considered a button element. This function will be called when it is - clicked. + + + prefix + - - - - - onClickSuffix - {"() => void"} - - - If defined, the suffix icon will be considered a button element. This function will be called when it is - clicked. - - - - - - prefixIcon - - string | {"(React.ReactNode & React.SVGProps )"} + {prefixTypeString} Material Symbol {" "} - name or SVG element as the icon that will be placed before the chip label. When using Material Symbols, - replace spaces with underscores. By default they are outlined if you want it to be filled prefix the - symbol name with "filled_". - - - - - - suffixIcon - - string | {"(React.ReactNode & React.SVGProps )"} - - - - Material Symbol - {" "} - name or SVG element as the icon that will be placed after the chip label. When using Material Symbols, - replace spaces with underscores. By default they are outlined if you want it to be filled prefix the - symbol name with "filled_". + name or SVG element used as the icon. When using Material Symbols, replace spaces with underscores. By + default, symbols are outlined; to use the filled version, prefix the symbol name with{" "} + "filled_". + + If a string or SVG is provided, it will be rendered as an icon placed before the chip label. If an + avatar props object is provided, a DxcAvatar will be displayed to the left of the label, only when the + chip size is medium or large. + - @@ -133,6 +145,14 @@ const sections = [ ), }, + { + title: "Avatar", + content: ( + <> + + + ), + }, ], }, ]; diff --git a/apps/website/screens/components/chip/code/examples/avatar.tsx b/apps/website/screens/components/chip/code/examples/avatar.tsx new file mode 100644 index 000000000..85d8dbd2a --- /dev/null +++ b/apps/website/screens/components/chip/code/examples/avatar.tsx @@ -0,0 +1,34 @@ +import { DxcChip, DxcFlex, DxcInset } from "@dxc-technology/halstack-react"; + +const code = `() => { + const icon = ( + + + + ); + + return ( + + + + console.log("action clicked") }} + /> + + + ); +}`; + +const scope = { + DxcChip, + DxcInset, + DxcFlex, +}; + +export default { code, scope }; diff --git a/apps/website/screens/components/chip/code/examples/icons.tsx b/apps/website/screens/components/chip/code/examples/icons.tsx index c49a98a49..7a61774a7 100644 --- a/apps/website/screens/components/chip/code/examples/icons.tsx +++ b/apps/website/screens/components/chip/code/examples/icons.tsx @@ -12,17 +12,14 @@ const code = `() => { ); - const onClickSuffix = () => { - console.log("Delete."); - }; - const onClickPrefix = () => { - console.log("Favorite."); - }; + return ( - - + + console.log("action clicked") }} + /> ); diff --git a/apps/website/screens/components/chip/overview/ChipOverviewPage.tsx b/apps/website/screens/components/chip/overview/ChipOverviewPage.tsx index 406df4d57..df86c5436 100644 --- a/apps/website/screens/components/chip/overview/ChipOverviewPage.tsx +++ b/apps/website/screens/components/chip/overview/ChipOverviewPage.tsx @@ -2,9 +2,10 @@ import { DxcBulletedList, DxcFlex, DxcLink, DxcParagraph, DxcTable } from "@dxc- import QuickNavContainer from "@/common/QuickNavContainer"; import DocFooter from "@/common/DocFooter"; import anatomy from "./images/chip-anatomy.png"; -import Example from "@/common/example/Example"; -import categorization from "./examples/categorization"; -import filter from "./examples/filter"; +import categorization from "./images/chip-categorization.png"; +import searchFilter from "./images/chip-faceted-search-filter.png"; +import states from "./images/chip-states.png"; +import sizeVariants from "./images/chip-size.png"; import spacing from "./images/chip-spacing.png"; import Image from "@/common/Image"; import Link from "next/link"; @@ -13,12 +14,18 @@ const sections = [ { title: "Introduction", content: ( - - Chips are versatile components that allow users to display and manage information in a compact format. They are - commonly used to represent selected options, tags, filters, or interactive elements within an interface. Their - lightweight and flexible design makes them ideal for enhancing user experience by enabling quick and organized - interactions. - + <> + + Chips are versatile UI components used to display and manage information in a compact, scannable format. They + commonly represent selected options, tags, filters, or contextual actions within an interface. + + + Chip component supports multiple sizes, optional leading elements (icon or avatar), and an optional action + icon, while maintaining a consistent structure and interaction model. Clear states, keyboard accessibility, + and controlled label length ensure the component remains lightweight, reusable, and adaptable across products + such as filters, forms, and the chatbot experience. + + ), }, { @@ -28,16 +35,20 @@ const sections = [ Chip anatomy - Prefix (Optional): the prefix can be an icon or an action icon that provides - additional context or functionality. + Container: the structural wrapper that holds the chip’s content and defines its visual + boundaries and spacing. It establishes the chip’s size and layout while remaining informational only. + + + Left Element (Optional): a leading visual element that adds contextual meaning to + the chip and helps users quickly recognize its purpose. - Label: the primary text that conveys the chip's meaning, such as a tag name or a selected - option. It should be concise, clear, and relevant to the chip's function. + Label: the text content inside the chip that identifies and describes the associated item + or value. - Suffix (Optional): the suffix can be an icon or an action icon that enhances - interactivity. + Action Icon (Optional): a trailing control that enables direct interaction with + the chip without affecting the container itself. @@ -51,11 +62,17 @@ const sections = [ content: ( <> - Chips are commonly used to organize content by grouping related topics, products, or subjects. They often - serve as a summary of the page's content. When using chips for categorization, ensure that they are - relevant to the displayed information to maintain clarity and usability. + Chips are used to organize and summarize related information such as topics, statuses, or attributes in a + compact and scannable way. They help users quickly understand key metadata without overwhelming the + interface. - + + With the redesigned Chip component, categorization chips support consistent sizing, optional leading + icons, and a clear visual structure while remaining informational and non-interactive. When using chips + for categorization, ensure labels are concise and relevant to the displayed content to maintain clarity + and usability. + + Chip categorization ), }, @@ -64,12 +81,29 @@ const sections = [ content: ( <> - When used alongside the select component, chips serve as effective filter facets, allowing users to refine - search results by choosing and removing specific attributes. This combination enables users to include or - exclude preferences directly from their queries. For faceted filtering, chips should be dismissible, - ensuring effortless adjustments and a more intuitive selection experience. + When used alongside selection or filter controls, chips act as filter facets that allow users to review, + apply, and remove selected attributes. This enables users to refine results efficiently and maintain + visibility of their current selections. + + + In the redesigned Chip component, faceted filter chips support dismissal through the action icon, which is + the primary interaction point. Clear visual states (hover, focus, active, disabled) help communicate + interactivity, while optional leading elements (icons or avatars, depending on size){" "} + + Chip faceted search filters + + ), + }, + { + title: "Chip states", + content: ( + <> + + Chip component, states are applied to the action icon only, including default, hover, focus, active, and + disabled. The container remains informational, ensuring interactions are clear, intentional, and + consistent across use cases. - + Chip states ), }, @@ -116,6 +150,19 @@ const sections = [ ), }, + { + title: "Size variants", + content: ( + <> + + The Chip component is available in three size variants to support different interface densities and use + cases. Each size follows the same structural pattern while adjusting spacing and supported elements to + maintain clarity and usability. + + Chip size variants + + ), + }, ], }, { @@ -134,6 +181,10 @@ const sections = [ Use sentence case for readability (e.g., "New York" instead of "NEW YORK"). + + Ensure the most important information appears at the beginning of the label, since long labels are + automatically truncated. + ), }, @@ -159,27 +210,22 @@ const sections = [ content: ( <> - While the component configuration is flexible enough to allow multiple icons or action icons, it is{" "} - not recommended to use two icons or two action icons within the same chip. Instead, a{" "} - balanced approach should be followed: pairing one icon (to provide - context) with one action icon (to enable an interaction). + Chip component may include one leading informational icon (or avatar) and{" "} + one action icon. Using multiple informational icons or multiple action icons within the + same chip is not supported. - Icons should add value to the chip, not just be decorative. + Informational icons should add value to the chip, such as status or category. - Ensure that icons are easy to recognize and understand within the chip's context. The - selected icon should accurately represent the chip's purpose, while the action icon should clearly - indicate the interaction it triggers. + The action icon should clearly communicate its purpose (e.g., remove or clear). - Icons should not compete for attention or convey conflicting messages. Instead, they - should complement each other to enhance usability. + Icons should be easy to recognize and not compete for attention. - Follow the guideline: one informational icon + one action icon (if needed) — avoid - using two icons of the same type. + Follow the guideline: one informational element + one action icon (if needed). @@ -190,10 +236,12 @@ const sections = [ content: ( - If there are too many chips in a row, consider horizontal scrolling or wrapping. + When displaying many chips, consider wrapping or horizontal scrolling depending on layout + constraints. - For dynamic content, provide a "Show more" option to avoid overwhelming the user. + For dynamic or long lists, provide a "Show more" or similar mechanism to prevent visual + clutter. ), diff --git a/apps/website/screens/components/chip/overview/images/chip-anatomy.png b/apps/website/screens/components/chip/overview/images/chip-anatomy.png index ef136349c..520478819 100644 Binary files a/apps/website/screens/components/chip/overview/images/chip-anatomy.png and b/apps/website/screens/components/chip/overview/images/chip-anatomy.png differ diff --git a/apps/website/screens/components/chip/overview/images/chip-categorization.png b/apps/website/screens/components/chip/overview/images/chip-categorization.png new file mode 100644 index 000000000..4ec9ffb0f Binary files /dev/null and b/apps/website/screens/components/chip/overview/images/chip-categorization.png differ diff --git a/apps/website/screens/components/chip/overview/images/chip-faceted-search-filter.png b/apps/website/screens/components/chip/overview/images/chip-faceted-search-filter.png new file mode 100644 index 000000000..ebd6abc09 Binary files /dev/null and b/apps/website/screens/components/chip/overview/images/chip-faceted-search-filter.png differ diff --git a/apps/website/screens/components/chip/overview/images/chip-size.png b/apps/website/screens/components/chip/overview/images/chip-size.png new file mode 100644 index 000000000..6ce475c74 Binary files /dev/null and b/apps/website/screens/components/chip/overview/images/chip-size.png differ diff --git a/apps/website/screens/components/chip/overview/images/chip-spacing.png b/apps/website/screens/components/chip/overview/images/chip-spacing.png index 960982e92..241f3625c 100644 Binary files a/apps/website/screens/components/chip/overview/images/chip-spacing.png and b/apps/website/screens/components/chip/overview/images/chip-spacing.png differ diff --git a/apps/website/screens/components/chip/overview/images/chip-states.png b/apps/website/screens/components/chip/overview/images/chip-states.png new file mode 100644 index 000000000..980e29cec Binary files /dev/null and b/apps/website/screens/components/chip/overview/images/chip-states.png differ diff --git a/packages/lib/src/action-icon/ActionIcon.tsx b/packages/lib/src/action-icon/ActionIcon.tsx index b4b521dce..11330e460 100644 --- a/packages/lib/src/action-icon/ActionIcon.tsx +++ b/packages/lib/src/action-icon/ActionIcon.tsx @@ -20,6 +20,7 @@ const ActionIconContainer = styled.div< hasAction?: boolean; size: ActionIconPropTypes["size"]; disabled?: ActionIconPropTypes["disabled"]; + isAvatar?: boolean; } & React.AnchorHTMLAttributes >` position: relative; @@ -40,15 +41,12 @@ const ActionIconContainer = styled.div< color: inherit; outline: none; } - ${({ hasAction, disabled, size }) => + + ${({ hasAction, disabled, size, isAvatar }) => !disabled && hasAction && css` cursor: pointer; - &:hover > div:first-child > div:first-child, - &:active > div:first-child > div:first-child { - display: block; - } &:focus:enabled > div:first-child, &:active:enabled > div:first-child { outline-style: solid; @@ -59,15 +57,37 @@ const ActionIconContainer = styled.div< &:focus-visible:enabled { outline: none; } + ${isAvatar + ? css` + &:hover > div:first-child > div:first-child, + &:active > div:first-child > div:first-child { + display: block; + } + ` + : css` + &:hover > div:first-child, + &:active > div:first-child { + background-color: var(--color-bg-alpha-light); + } + `} `} - ${({ disabled }) => + + ${({ disabled, isAvatar }) => disabled && css` cursor: not-allowed; - & > div:first-child > div:first-child { - display: block; - background-color: rgba(255, 255, 255, 0.5); - } + ${isAvatar + ? css` + & > div:first-child > div:first-child { + display: block; + background-color: rgba(255, 255, 255, 0.5); + } + ` + : css` + & > div:first-child > div:first-child { + color: var(--color-fg-neutral-medium); + } + `} `} `; @@ -155,9 +175,10 @@ const ForwardedActionIcon = forwardRef( aria-label={(onClick || linkHref) && (ariaLabel || title || "Action Icon")} disabled={disabled} ref={ref} + isAvatar={color !== "transparent"} > - {(!!onClick || !!linkHref) &&