From 4d9d1bf0f416eba57512f4b01e82b0bdd0ed3bfe Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Fri, 14 Aug 2026 09:39:58 -0300 Subject: [PATCH 1/4] feat(chip): add chip component --- .../documentation/components/Chip.stories.tsx | 43 +++++++++++++++- frontend/web/components/base/Chip/Chip.scss | 19 +++++++ frontend/web/components/base/Chip/Chip.tsx | 20 ++++++-- frontend/web/components/base/Chip/ChipDot.tsx | 6 +++ frontend/web/components/base/Chip/index.ts | 1 + .../experiments/StatusBadge/StatusBadge.scss | 51 ------------------- .../experiments/StatusBadge/StatusBadge.tsx | 23 +++++---- 7 files changed, 98 insertions(+), 65 deletions(-) create mode 100644 frontend/web/components/base/Chip/ChipDot.tsx delete mode 100644 frontend/web/components/experiments/StatusBadge/StatusBadge.scss diff --git a/frontend/documentation/components/Chip.stories.tsx b/frontend/documentation/components/Chip.stories.tsx index c88fe9860935..97841220196e 100644 --- a/frontend/documentation/components/Chip.stories.tsx +++ b/frontend/documentation/components/Chip.stories.tsx @@ -1,7 +1,7 @@ import React from 'react' import type { Meta, StoryObj } from 'storybook' -import Chip from 'components/base/Chip' +import Chip, { ChipDot } from 'components/base/Chip' const meta: Meta = { args: { children: 'Production' }, @@ -11,7 +11,7 @@ const meta: Meta = { docs: { description: { component: - 'Canonical token-based chip primitive: a small labelled pill token. Layout via Bootstrap utilities, colour/radius via token utilities, padding/sizes/border/truncation in SCSS. Leading/trailing icons go in as children. Selection lives in ToggleChip and count badges are a separate Badge concern. The legacy `.chip` (old SCSS vars + manual dark-mode block, ~35×) migrates onto this under #6606.', + 'Canonical token-based chip primitive: a small labelled pill token. Layout via Bootstrap utilities, colour/radius via token utilities, padding/sizes/border/truncation in SCSS. Leading/trailing icons go in as children. `variant` covers neutral, accent and the four status colours; `pill` gives the fully rounded ends that status and count badges use, and `ChipDot` adds the leading dot in `currentColor`. Selection lives in ToggleChip. The legacy `.chip` (old SCSS vars + manual dark-mode block, ~35×) migrates onto this under #6606.', }, }, layout: 'centered', @@ -38,6 +38,45 @@ export const Sizes: Story = { ), } +export const StatusVariants: Story = { + render: () => ( +
+ + + Draft + + + + Running + + + + Paused + + + + Completed + +
+ ), +} + +export const Counts: Story = { + render: () => ( +
+ + 5 + + + 0 + + + 128 + +
+ ), +} + export const Removable: Story = { args: { children: 'feature-flag', onRemove: () => undefined }, } diff --git a/frontend/web/components/base/Chip/Chip.scss b/frontend/web/components/base/Chip/Chip.scss index 854427ce3f98..c55b84a31c2c 100644 --- a/frontend/web/components/base/Chip/Chip.scss +++ b/frontend/web/components/base/Chip/Chip.scss @@ -13,6 +13,25 @@ border-color: var(--color-border-action); } + // Status colours carry their meaning in the fill, so an outline only adds + // noise. Transparent rather than removed, so a status chip is the same + // height as a bordered one beside it. + &--success, + &--warning, + &--info, + &--muted { + border-color: transparent; + } + + // Status dot. currentColor, so it follows the variant with nothing to wire. + &__dot { + width: 6px; + height: 6px; + border-radius: var(--radius-full); + background: currentColor; + flex-shrink: 0; + } + // Sizes (default is the base above). &--sm { padding: 3px 8px; diff --git a/frontend/web/components/base/Chip/Chip.tsx b/frontend/web/components/base/Chip/Chip.tsx index 296219372dda..014bcfad0627 100644 --- a/frontend/web/components/base/Chip/Chip.tsx +++ b/frontend/web/components/base/Chip/Chip.tsx @@ -5,12 +5,20 @@ import { colorIconSecondary } from 'common/theme/tokens' import './Chip.scss' export type ChipSize = 'default' | 'sm' | 'xs' -export type ChipVariant = 'neutral' | 'accent' +export type ChipVariant = + | 'neutral' + | 'accent' + | 'success' + | 'warning' + | 'info' + | 'muted' export type ChipProps = { children: ReactNode variant?: ChipVariant size?: ChipSize + /** Fully rounded ends, for status and count badges. */ + pill?: boolean truncate?: boolean onRemove?: () => void onClick?: () => void @@ -30,7 +38,11 @@ export type ChipProps = { // bg + text come from token utilities; the variant border lives in Chip.scss. const VARIANT_UTILITIES: Record = { accent: 'bg-surface-action-subtle text-action', + info: 'bg-surface-info text-info', + muted: 'bg-surface-muted text-secondary', neutral: 'bg-surface-subtle text-default', + success: 'bg-surface-success text-success', + warning: 'bg-surface-warning text-warning', } // Token-based chip primitive. Uses `ds-chip` rather than the legacy `.chip` @@ -46,6 +58,7 @@ const Chip = ({ onClick, onKeyDown, onRemove, + pill = false, ref, role, size = 'default', @@ -58,10 +71,11 @@ const Chip = ({