diff --git a/frontend/documentation/components/Chip.stories.tsx b/frontend/documentation/components/Chip.stories.tsx index c88fe9860935..77269719397e 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, the five status colours and `solid`; `ChipDot` adds the leading dot in `currentColor`. Radius is a fixed 6px from the tags frame, so there is no shape prop. Selection lives in ToggleChip. The legacy `.chip` (old SCSS vars + manual dark-mode block, ~35×) migrates onto this under #6606.', }, }, layout: 'centered', @@ -28,6 +28,10 @@ export const Accent: Story = { args: { children: '"hello"', variant: 'accent' }, } +export const Solid: Story = { + args: { children: 'Enterprise', variant: 'solid' }, +} + export const Sizes: Story = { render: () => (
@@ -38,6 +42,49 @@ export const Sizes: Story = { ), } +export const StatusVariants: Story = { + render: () => ( +
+ + + Draft + + + + Running + + + + Paused + + + + Failed + + + + 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..3407d57ff58d 100644 --- a/frontend/web/components/base/Chip/Chip.scss +++ b/frontend/web/components/base/Chip/Chip.scss @@ -13,13 +13,38 @@ 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, + &--danger, + &--info, + &--muted, + &--solid { + 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; font-size: 0.75rem; } + // 24px is fixed in the tags frame, so it is stated rather than left to derive + // from the inherited line-height. The frame's 8px vertical padding is an + // artefact of a height override on the auto-layout and is not applied. &--xs { + height: 24px; padding: 1px 6px; font-size: 0.6875rem; } diff --git a/frontend/web/components/base/Chip/Chip.tsx b/frontend/web/components/base/Chip/Chip.tsx index 296219372dda..e68d7b2e89f5 100644 --- a/frontend/web/components/base/Chip/Chip.tsx +++ b/frontend/web/components/base/Chip/Chip.tsx @@ -5,7 +5,15 @@ 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' + | 'danger' + | 'info' + | 'muted' + | 'solid' export type ChipProps = { children: ReactNode @@ -30,7 +38,17 @@ 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', + danger: 'bg-surface-danger text-danger', + info: 'bg-surface-info text-info', + muted: 'bg-surface-muted text-secondary', neutral: 'bg-surface-subtle text-default', + // The one filled variant. `text-white` rather than a token because there is + // no inverse-text token yet; white on --color-surface-action is 5.93:1, so AA + // but not AAA. Note the app has a second, darker solid (`bg-primary900`, used + // by BetaFlag and PlanBasedAccess) that this deliberately does not cover. + solid: 'bg-surface-action text-white', + success: 'bg-surface-success text-success', + warning: 'bg-surface-warning text-warning', } // Token-based chip primitive. Uses `ds-chip` rather than the legacy `.chip` @@ -58,10 +76,12 @@ const Chip = ({