@@ -19,6 +19,8 @@ type ParticipantCountBarProps = {
1919 onUnpaintedGroupedChange ?: ( isGrouped : boolean ) => void ;
2020 isProportional ?: boolean ;
2121 className ?: string ;
22+ /** Display mask parallel to pointGroups: true = visible, false = hidden. When undefined, all points counted. */
23+ displayMask ?: boolean [ ] ;
2224} ;
2325
2426export const ParticipantCountBar : React . FC < ParticipantCountBarProps > = ( {
@@ -27,6 +29,7 @@ export const ParticipantCountBar: React.FC<ParticipantCountBarProps> = ({
2729 onUnpaintedGroupedChange,
2830 isProportional = true ,
2931 className,
32+ displayMask,
3033} ) => {
3134 // Internal state for uncontrolled mode
3235 const [ internalIsUnpaintedGrouped , setInternalIsUnpaintedGrouped ] = React . useState ( false ) ;
@@ -41,14 +44,16 @@ export const ParticipantCountBar: React.FC<ParticipantCountBarProps> = ({
4144 let unpaintedGroup : PointGroupData | null = null ;
4245 const groupCounts = new Map < number , number > ( ) ;
4346
44- // Count occurrences of each group
45- pointGroups . forEach ( group => {
47+ // Count occurrences of each group (skip masked participants)
48+ pointGroups . forEach ( ( group , i ) => {
49+ if ( displayMask && ! displayMask [ i ] ) return ;
4650 groupCounts . set ( group , ( groupCounts . get ( group ) || 0 ) + 1 ) ;
4751 } ) ;
4852
4953 // Handle unpainted group separately
5054 let unpaintedCount = 0 ;
51- pointGroups . forEach ( group => {
55+ pointGroups . forEach ( ( group , i ) => {
56+ if ( displayMask && ! displayMask [ i ] ) return ;
5257 if ( group === UNPAINTED_VALUE ) {
5358 unpaintedCount ++ ;
5459 }
@@ -75,13 +80,15 @@ export const ParticipantCountBar: React.FC<ParticipantCountBarProps> = ({
7580 }
7681
7782 return { coloredGroups, unpaintedGroup } ;
78- } , [ pointGroups ] ) ;
83+ } , [ pointGroups , displayMask ] ) ;
7984
8085 // Calculate proportional widths if needed
8186 const proportionalData = React . useMemo ( ( ) => {
8287 if ( ! isProportional ) return null ;
8388
84- const totalPoints = pointGroups . length ;
89+ const totalPoints = displayMask
90+ ? displayMask . filter ( Boolean ) . length
91+ : pointGroups . length ;
8592 if ( totalPoints === 0 ) return null ;
8693
8794 // Calculate total number of badges - no gaps between colored badges now
@@ -99,7 +106,9 @@ export const ParticipantCountBar: React.FC<ParticipantCountBarProps> = ({
99106 } else {
100107 // All badges (including unpainted if grouped) share space proportionally
101108 // Calculate total excluding unpainted points when they're not grouped
102- const unpaintedPoints = pointGroups . filter ( group => group === UNPAINTED_VALUE ) . length ;
109+ const unpaintedPoints = pointGroups . filter ( ( group , i ) =>
110+ group === UNPAINTED_VALUE && ( ! displayMask || displayMask [ i ] )
111+ ) . length ;
103112 coloredPointsTotal = totalPoints - ( groupData . unpaintedGroup && ! isUnpaintedGrouped ? unpaintedPoints : 0 ) ;
104113 availableWidthPercent = 100 ;
105114 }
@@ -122,7 +131,7 @@ export const ParticipantCountBar: React.FC<ParticipantCountBarProps> = ({
122131 totalBadges,
123132 gapWidth
124133 } ;
125- } , [ groupData , isProportional , pointGroups . length , isUnpaintedGrouped ] ) ;
134+ } , [ groupData , isProportional , pointGroups , isUnpaintedGrouped , displayMask ] ) ;
126135
127136 const handleUnpaintedClick = ( ) => {
128137 const newValue = ! isUnpaintedGrouped ;
0 commit comments