From 096f299f546784a234a98821dbcbbf4f35795749 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 10 Jun 2026 00:46:37 -0400 Subject: [PATCH 1/3] Replace control status badge icons with new agreed upon icons I do not think that we should implement filled icons. Nonetheless, this direction was decided upon by JD on June 4th, 2026 and will be implemented accordingly. --- packages/ui/package.json | 2 +- .../control-status-badge.tsx | 35 +++++++------------ pnpm-lock.yaml | 18 ++++++++-- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index 93b1b25..87b416b 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -59,7 +59,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", - "lucide-react": "^0.545.0", + "lucide-react": "^1.17.0", "motion": "^12.23.24", "react-hook-form": "^7.63.0", "react-syntax-highlighter": "^16.1.0", diff --git a/packages/ui/src/components/control-status-badge/control-status-badge.tsx b/packages/ui/src/components/control-status-badge/control-status-badge.tsx index aa4a70c..0522fb9 100644 --- a/packages/ui/src/components/control-status-badge/control-status-badge.tsx +++ b/packages/ui/src/components/control-status-badge/control-status-badge.tsx @@ -29,7 +29,7 @@ const getStatusConfig = (status: string) => { }; case 'not-started': return { - icon: 'Circle', + icon: 'CircleDashed', className: styles['badge--not-started'], label: 'Not Started', }; @@ -49,7 +49,7 @@ const getStatusConfig = (status: string) => { return { icon: 'MessageCircle', className: styles['badge--comment'], - label: 'Comment', + label: 'In Review: General', }; case 'not-applicable': return { @@ -59,37 +59,31 @@ const getStatusConfig = (status: string) => { }; case 'accepted': return { - icon: , + icon: 'MessageCircleCheck', className: styles['badge--accepted'], - label: 'Accepted', + label: 'In Review: Accepted', }; case 'questioned': return { icon: 'MessageCircleQuestion', className: styles['badge--question'], - label: 'Questioned', - }; - case 'general': - return { - icon: 'MessageCircle', - className: styles['badge--comment'], - label: 'General', + label: 'In Review: Questioned', }; case 'compliant': return { - icon: 'Check', + icon: , className: styles['badge--compliant'], label: 'Compliant', }; case 'non-compliant': return { - icon: 'TriangleAlert', + icon: 'X', className: styles['badge--non-compliant'], label: 'Non-compliant', }; default: return { - icon: 'Circle', + icon: 'CircleDashed', className: styles['badge--not-started'], label: status, }; @@ -98,8 +92,8 @@ const getStatusConfig = (status: string) => { export { ControlStatusBadge }; -// TODO: Remove and replace with Lucide icon once PR #3770 gets merged into their repo. -const MessageCircleCheckIcon = ({ className }: { className?: string }) => { +// Custom filled icon — intentionally uses a fill, which Lucide's icon set never does. +const CircleCheckFillIcon = ({ className }: { className?: string }) => { return ( { width="12" height="12" viewBox="0 0 24 24" - fill="none" - stroke="currentColor" - stroke-width="2" - stroke-linecap="round" - stroke-linejoin="round" + fill="currentColor" > - - + ); }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d941c03..0268530 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -187,8 +187,8 @@ importers: specifier: ^1.1.1 version: 1.1.1(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) lucide-react: - specifier: ^0.545.0 - version: 0.545.0(react@19.2.0) + specifier: ^1.17.0 + version: 1.17.0(react@19.2.0) motion: specifier: ^12.23.24 version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -5415,6 +5415,14 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lucide-react@1.17.0: + resolution: + { + integrity: sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==, + } + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + magic-string@0.30.19: resolution: { @@ -8213,7 +8221,7 @@ snapshots: '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.6 + '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -11311,6 +11319,10 @@ snapshots: dependencies: react: 19.2.0 + lucide-react@1.17.0(react@19.2.0): + dependencies: + react: 19.2.0 + magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 From 1fbc78c25436467055766e8d3e2f654a8000e2cb Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 10 Jun 2026 00:57:23 -0400 Subject: [PATCH 2/3] Implement split badge --- .../control-status-badge.module.css | 31 +++++++++++ .../control-status-badge.tsx | 54 ++++++++++++++++--- 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/components/control-status-badge/control-status-badge.module.css b/packages/ui/src/components/control-status-badge/control-status-badge.module.css index affbefe..6969a2f 100644 --- a/packages/ui/src/components/control-status-badge/control-status-badge.module.css +++ b/packages/ui/src/components/control-status-badge/control-status-badge.module.css @@ -54,3 +54,34 @@ --badge-bg-color: var(--color-badge-background-compliant); --badge-fg-color: var(--color-badge-text-compliant); } + +/* "In Review" segmented pill: a filled status segment joined to a + border-only sub-status segment. The status color tokens are inherited + from the .badge--* class applied alongside .split-badge. */ +.split-badge { + @apply inline-flex w-max items-center; + @apply text-xs font-medium tabular-nums; +} + +.split-badge__status { + @apply inline-flex items-center gap-1; + @apply min-h-5 px-2 py-0.5; + @apply rounded-l-full; + border: 1px solid transparent; + background-color: var(--badge-bg-color); + color: var(--badge-fg-color); +} + +.split-badge__sub-status { + @apply inline-flex items-center; + @apply min-h-5 px-2 py-0.5; + @apply rounded-r-full; + /* Overlap the status segment so the divider reads as a single 1px line. */ + margin-left: -1px; + border: 1px solid var(--badge-bg-color); + color: var(--badge-fg-color); +} + +.split-badge .icon { + @apply text-inherit; +} diff --git a/packages/ui/src/components/control-status-badge/control-status-badge.tsx b/packages/ui/src/components/control-status-badge/control-status-badge.tsx index 0522fb9..7b53d3c 100644 --- a/packages/ui/src/components/control-status-badge/control-status-badge.tsx +++ b/packages/ui/src/components/control-status-badge/control-status-badge.tsx @@ -1,5 +1,9 @@ +import type { ReactElement } from 'react'; + import { Badge, type BadgeDisplayMode } from '@/components/badge/badge'; import styles from '@/components/control-status-badge/control-status-badge.module.css'; +import { Icon } from '@/components/icon/icon'; +import { cn } from '@/lib/utils'; export type ControlStatusBadgeDisplayMode = BadgeDisplayMode; @@ -8,9 +12,42 @@ interface ControlStatusBadgeProps { display?: ControlStatusBadgeDisplayMode; } +interface StatusConfig { + icon: string | ReactElement; + className: string; + label: string; + // When present, the badge renders as a segmented pill: a filled status + // segment ("In Review") followed by a border-only sub-status segment. + subLabel?: string; +} + const ControlStatusBadge = ({ status, display = 'both' }: ControlStatusBadgeProps) => { const config = getStatusConfig(status); + // "In Review" statuses split into a filled status + a border-only sub-status. + if (config.subLabel) { + // Icon-only collapses to just the filled "In Review" indicator. + if (display === 'icon-only') { + return ( + + {config.label} + + ); + } + + return ( +
+ + {display !== 'text-only' && ( + + )} + {config.label} + + {config.subLabel} +
+ ); + } + return ( {config.label} @@ -19,7 +56,7 @@ const ControlStatusBadge = ({ status, display = 'both' }: ControlStatusBadgeProp }; // Helper function -const getStatusConfig = (status: string) => { +const getStatusConfig = (status: string): StatusConfig => { switch (status) { case 'in-progress': return { @@ -47,9 +84,10 @@ const getStatusConfig = (status: string) => { }; case 'comment': return { - icon: 'MessageCircle', + icon: 'Eye', className: styles['badge--comment'], - label: 'In Review: General', + label: 'In Review', + subLabel: 'General', }; case 'not-applicable': return { @@ -59,15 +97,17 @@ const getStatusConfig = (status: string) => { }; case 'accepted': return { - icon: 'MessageCircleCheck', + icon: 'Eye', className: styles['badge--accepted'], - label: 'In Review: Accepted', + label: 'In Review', + subLabel: 'Accepted', }; case 'questioned': return { - icon: 'MessageCircleQuestion', + icon: 'Eye', className: styles['badge--question'], - label: 'In Review: Questioned', + label: 'In Review', + subLabel: 'Questioned', }; case 'compliant': return { From 0cfe26695f179859a366c9caaa9c2579f0191e85 Mon Sep 17 00:00:00 2001 From: Henry Wilkinson Date: Wed, 10 Jun 2026 01:12:00 -0400 Subject: [PATCH 3/3] Update package.json --- packages/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index ed30edf..2968544 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -2,7 +2,7 @@ "name": "@eqtylab/equality", "description": "EQTYLab's component and token-based design system", "homepage": "https://equality.eqtylab.io/", - "version": "2.1.0", + "version": "2.1.1", "license": "Apache-2.0", "keywords": [ "component library",