Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
37a6d60
Update badge styles
abzokhattab Feb 12, 2026
07fc7e4
fix badges styles
abzokhattab Feb 16, 2026
0d3261c
fixing prettier
abzokhattab Feb 16, 2026
09dd0a9
Merge remote-tracking branch 'origin/main' into refactor-badge-conden…
abzokhattab Feb 17, 2026
aaa30a8
bringing back textStyles at domainslistrow
abzokhattab Feb 17, 2026
42ea650
Add colored text for outlined success/danger badges and update badge …
abzokhattab Feb 19, 2026
2d212b9
Add colored text for outlined success/danger badges and update badge …
abzokhattab Feb 19, 2026
57760b6
fixing tasklistitemrow
abzokhattab Feb 19, 2026
db279c0
Widen badgeStyle type to StyleProp<ViewStyle> and wire up strong badg…
abzokhattab Feb 21, 2026
3fad8eb
Merge remote-tracking branch 'origin/main' into refactor-badge-conden…
abzokhattab Feb 21, 2026
c69f4e3
refactoring
abzokhattab Feb 21, 2026
9e1b3f7
handling default hover
abzokhattab Feb 21, 2026
4075c9d
fixing eslint
abzokhattab Feb 21, 2026
a3180c7
cleanup
abzokhattab Feb 21, 2026
0f1ce9c
cleanup
abzokhattab Feb 21, 2026
ae767cd
fixing badge focus layout
abzokhattab Feb 21, 2026
e237775
cleanup
abzokhattab Feb 22, 2026
2854b42
fixing eslint and sentry labels
abzokhattab Feb 22, 2026
44216c4
Minor refactoring in menuitem
abzokhattab Feb 22, 2026
60de335
fixing domain badge style
abzokhattab Feb 22, 2026
2a686e0
Simplify badge to 3 solid types (Default, Success, Danger) and update…
abzokhattab Feb 24, 2026
e3b3700
Merge origin/main into refactor-badge-condensed-strong-variants
abzokhattab Feb 24, 2026
82525d9
fixing prettier
abzokhattab Feb 24, 2026
2c7c284
fixing ts
abzokhattab Feb 24, 2026
2af5925
Apply design feedback: condensed counters, buttonPressedBG for defaul…
abzokhattab Feb 24, 2026
50051db
Refactor Badge to support strong, condensed, and non-strong variants …
abzokhattab Feb 26, 2026
5e29d13
Merge remote-tracking branch 'origin/main' into refactor-badge-conden…
abzokhattab Feb 26, 2026
dfc6bf3
making completed badge as success
abzokhattab Feb 26, 2026
de12ef6
fixing ts
abzokhattab Feb 26, 2026
e41d621
Merge remote-tracking branch 'origin' into refactor-badge-condensed-s…
abzokhattab Feb 27, 2026
ee1dd8c
Final badge adjustments: match Figma specs, restore isStrong, fix act…
abzokhattab Feb 27, 2026
212f175
fixing prettier
abzokhattab Feb 27, 2026
b509f9b
styles cleanup
abzokhattab Feb 27, 2026
ac542fd
Use regular size for report counters, remove redundant success prop, …
abzokhattab Mar 2, 2026
e43c0ba
Merge origin/main, resolve WorkspacesListRow conflict
abzokhattab Mar 2, 2026
49657a3
Remove fixed height from defaultBadge so condensed minHeight can over…
abzokhattab Mar 2, 2026
37409cc
Fix badge review issues: remove stale dep, match border on focus, dro…
abzokhattab Mar 2, 2026
acec444
Merge origin/main, resolve WorkspacesListRow conflict
abzokhattab Mar 3, 2026
bf20282
Extract StatusBadge component to DRY up condensed status badge pattern
abzokhattab Mar 3, 2026
63d8469
Rename badge boolean props to use is prefix, extract StatusBadge wrapper
abzokhattab Mar 3, 2026
30c5f08
Merge remote-tracking branch 'origin/main' into refactor-badge-conden…
abzokhattab Mar 3, 2026
11de51f
Merge remote-tracking branch 'origin/main' into refactor-badge-conden…
abzokhattab Mar 3, 2026
a813cac
Merge remote-tracking branch 'origin/main' into refactor-badge-conden…
abzokhattab Mar 3, 2026
332f967
Merge origin/main, resolve MoneyRequestReportPreviewContent conflict
abzokhattab Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions src/components/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ type BadgeProps = {
/** Is Error type */
error?: boolean;

/** Whether badge uses strong (filled) style instead of outlined */
isStrong?: boolean;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strong to me indicates bold. Why not isFilled if it's determining whether it is filled or not?


/** Whether badge uses condensed (smaller) sizing */
isCondensed?: boolean;

/** Whether badge is clickable */
pressable?: boolean;

Expand Down Expand Up @@ -51,6 +57,8 @@ type BadgeProps = {
function Badge({
success = false,
error = false,
isStrong = false,
isCondensed = false,
pressable = false,
text,
environment = CONST.ENVIRONMENT.DEV,
Expand All @@ -68,17 +76,20 @@ function Badge({

const isDeleted = style && Array.isArray(style) ? style.includes(styles.offlineFeedbackDeleted) : false;

const iconColor = StyleUtils.getIconColorStyle(success, error);
const iconColor = StyleUtils.getIconColorStyle(success, error, isStrong);

const iconSize = isCondensed || shouldUseXXSmallIcon ? variables.iconSizeXXSmall : variables.iconSizeExtraSmall;

const wrapperStyles: (state: PressableStateCallbackType) => StyleProp<ViewStyle> = useCallback(
({pressed}) => [
styles.defaultBadge,
isCondensed && styles.condensedBadge,
styles.alignSelfCenter,
styles.ml2,
StyleUtils.getBadgeColorStyle(success, error, pressed, environment === CONST.ENVIRONMENT.ADHOC),
StyleUtils.getBadgeColorStyle(success, error, pressed, environment === CONST.ENVIRONMENT.ADHOC, isStrong),
badgeStyles,
],
[styles.defaultBadge, styles.alignSelfCenter, styles.ml2, StyleUtils, success, error, environment, badgeStyles],
[styles.defaultBadge, styles.condensedBadge, styles.alignSelfCenter, styles.ml2, StyleUtils, success, error, environment, badgeStyles, isCondensed, isStrong],
);

return (
Expand All @@ -93,15 +104,25 @@ function Badge({
{!!icon && (
<View style={[styles.mr2, iconStyles]}>
<Icon
width={shouldUseXXSmallIcon ? variables.iconSizeXXSmall : variables.iconSizeExtraSmall}
height={shouldUseXXSmallIcon ? variables.iconSizeXXSmall : variables.iconSizeExtraSmall}
width={iconSize}
height={iconSize}
src={icon}
fill={iconColor}
/>
</View>
)}
<Text
style={[styles.badgeText, styles.textStrong, textStyles, isDeleted ? styles.offlineFeedbackDeleted : {}]}
style={[
styles.badgeText,
styles.textStrong,
isCondensed && styles.condensedBadgeText,
!isStrong && !success && !error && styles.badgeDefaultText,
!isStrong && success && styles.badgeSuccessText,
!isStrong && error && styles.badgeDangerText,
isStrong && (success || error) && styles.badgeStrongText,
textStyles,
isDeleted ? styles.offlineFeedbackDeleted : {},
]}
numberOfLines={1}
>
{text}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Domain/DomainsListRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ function DomainsListRow({title, isHovered, badgeText, brickRoadIndicator, menuIt
<TextWithTooltip
text={title}
shouldShowTooltip
style={styles.textStrong}
style={[styles.textStrong, styles.flexShrink1]}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flexShrink1 fixes the following issue on mobile where currently the three dots are moving on top of the badge ....

i couldnt have clear steps to test this but i added mock data to verify

Image

/>

{!!badgeText && (
<View style={[styles.flexRow, styles.gap2, styles.alignItemsCenter, styles.justifyContentEnd]}>
<Badge
text={badgeText}
textStyles={styles.textStrong}
badgeStyles={[styles.alignSelfCenter, styles.badgeBordered]}
badgeStyles={styles.alignSelfCenter}
/>
</View>
)}
Expand Down
38 changes: 29 additions & 9 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,13 @@ type MenuItemBaseProps = ForwardedFSClassProps &
badgeIcon?: IconAsset;

/** Whether the badge should be shown as success */
badgeSuccess?: boolean;
isBadgeSuccess?: boolean;

/** Whether the badge should use strong (filled) variant */
isBadgeStrong?: boolean;

/** Whether the badge should use condensed (smaller) sizing */
isBadgeCondensed?: boolean;

/** Callback to fire when the badge is pressed */
onBadgePress?: (event?: GestureResponderEvent | KeyboardEvent) => void;
Expand All @@ -109,7 +115,7 @@ type MenuItemBaseProps = ForwardedFSClassProps &
titleStyle?: StyleProp<TextStyle>;

/** Any additional styles to apply on the badge element */
badgeStyle?: ViewStyle;
badgeStyle?: StyleProp<ViewStyle>;

/** Any additional styles to apply to the label */
labelStyle?: StyleProp<ViewStyle>;
Expand Down Expand Up @@ -451,7 +457,9 @@ function MenuItem({
onPress,
badgeText,
badgeIcon,
badgeSuccess,
isBadgeSuccess,
isBadgeStrong,
isBadgeCondensed,
onBadgePress,
shouldShowBadgeInSeparateRow = false,
shouldShowBadgeBelow = false,
Expand Down Expand Up @@ -980,8 +988,16 @@ function MenuItem({
<Badge
text={badgeText}
icon={badgeIcon}
badgeStyles={[badgeStyle, styles.alignSelfStart, styles.ml3, styles.mt2]}
success={badgeSuccess}
badgeStyles={[
badgeStyle,
styles.alignSelfStart,
styles.ml3,
styles.mt2,
focused && !isBadgeSuccess && styles.badgeDefaultActive,
]}
success={isBadgeSuccess}
isStrong={isBadgeStrong}
isCondensed={isBadgeCondensed}
onPress={onBadgePress}
pressable={!!onBadgePress}
/>
Expand All @@ -996,8 +1012,10 @@ function MenuItem({
<Badge
text={badgeText}
icon={badgeIcon}
badgeStyles={badgeStyle}
success={badgeSuccess}
badgeStyles={[badgeStyle, focused && !isBadgeSuccess && styles.badgeDefaultActive]}
success={isBadgeSuccess}
isStrong={isBadgeStrong}
isCondensed={isBadgeCondensed}
onPress={onBadgePress}
pressable={!!onBadgePress}
/>
Expand Down Expand Up @@ -1094,8 +1112,10 @@ function MenuItem({
<Badge
text={badgeText}
icon={badgeIcon}
badgeStyles={[badgeStyle, styles.alignSelfStart, styles.ml13, styles.mt2]}
success={badgeSuccess}
badgeStyles={[badgeStyle, styles.alignSelfStart, styles.ml13, styles.mt2, focused && !isBadgeSuccess && styles.badgeDefaultActive]}
success={isBadgeSuccess}
isStrong={isBadgeStrong}
isCondensed={isBadgeCondensed}
onPress={onBadgePress}
pressable={!!onBadgePress}
/>
Expand Down
19 changes: 7 additions & 12 deletions src/components/ParentNavigationSubtitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import StatusBadge from './StatusBadge';
import Text from './Text';
import TextLink from './TextLink';

Expand Down Expand Up @@ -189,18 +190,12 @@ function ParentNavigationSubtitle({
return (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.w100]}>
{!!statusText && (
<View
style={[
styles.reportStatusContainer,
styles.mr1,
{
backgroundColor: statusTextBackgroundColor,
},
statusTextContainerStyles,
]}
>
<Text style={[styles.reportStatusText, {color: statusTextColor}]}>{statusText}</Text>
</View>
<StatusBadge
text={statusText}
backgroundColor={statusTextBackgroundColor}
textColor={statusTextColor}
badgeStyles={[styles.mr1, statusTextContainerStyles]}
/>
)}
<Text
style={[styles.optionAlternateText, styles.textLabelSupporting, styles.flexShrink1, styles.mnw0, textStyles]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ExportWithDropdownMenu from '@components/ReportActionItem/ExportWithDropd
import AnimatedSettlementButton from '@components/SettlementButton/AnimatedSettlementButton';
import type {PaymentActionParams} from '@components/SettlementButton/types';
import {showContextMenuForReport} from '@components/ShowContextMenuContext';
import StatusBadge from '@components/StatusBadge';
import Text from '@components/Text';
import useConfirmModal from '@hooks/useConfirmModal';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
Expand Down Expand Up @@ -885,26 +886,12 @@ function MoneyRequestReportPreviewContent({
(shouldShowReportStatus || !shouldShowAccessPlaceHolder) && (
<View style={[styles.flexRow, styles.justifyContentStart, styles.alignItemsCenter]}>
{shouldShowReportStatus && (
<View
style={[
styles.reportStatusContainer,
styles.mr1,
{
backgroundColor: reportStatusColorStyle?.backgroundColor,
},
]}
>
<Text
style={[
styles.reportStatusText,
{
color: reportStatusColorStyle?.textColor,
},
]}
>
{reportStatus}
</Text>
</View>
<StatusBadge
text={reportStatus}
backgroundColor={reportStatusColorStyle?.backgroundColor}
textColor={reportStatusColorStyle?.textColor}
badgeStyles={styles.mr1}
/>
)}
{!shouldShowAccessPlaceHolder && <Text style={[styles.textLabelSupporting, styles.lh16]}>{expenseCount}</Text>}
</View>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import {View} from 'react-native';
import Badge from '@components/Badge';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
Expand All @@ -14,19 +13,18 @@ import actionTranslationsMap from './actionTranslationsMap';
type BadgeActionCellProps = {
action: SearchTransactionAction;
isLargeScreenWidth: boolean;
isSelected: boolean;
extraSmall: boolean;
shouldDisablePointerEvents?: boolean;
};

function BadgeActionCell({action, isLargeScreenWidth, isSelected, extraSmall, shouldDisablePointerEvents}: BadgeActionCellProps) {
function BadgeActionCell({action, isLargeScreenWidth, shouldDisablePointerEvents}: BadgeActionCellProps) {
const {translate} = useLocalize();
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Checkmark', 'Checkbox']);
const text = translate(actionTranslationsMap[action]);

const badgeTheme = action === CONST.SEARCH.ACTION_TYPES.PAID ? theme.reportStatusBadge.paid : theme.reportStatusBadge.approved;

return (
<View
style={[StyleUtils.getHeight(variables.h20), styles.justifyContentCenter, shouldDisablePointerEvents && styles.pointerEventsNone]}
Expand All @@ -35,20 +33,14 @@ function BadgeActionCell({action, isLargeScreenWidth, isSelected, extraSmall, sh
>
<Badge
text={text}
icon={action === CONST.SEARCH.ACTION_TYPES.DONE ? expensifyIcons.Checkbox : expensifyIcons.Checkmark}
isCondensed
badgeStyles={[
styles.ml0,
styles.ph2,
styles.gap1,
styles.borderNone,
isLargeScreenWidth ? styles.alignSelfCenter : styles.alignSelfEnd,
StyleUtils.getHeight(variables.h20),
StyleUtils.getMinimumHeight(variables.h20),
isSelected ? StyleUtils.getBorderColorStyle(theme.buttonHoveredBG) : StyleUtils.getBorderColorStyle(theme.border),
StyleUtils.getBackgroundColorStyle(badgeTheme.backgroundColor),
]}
textStyles={StyleUtils.getFontSizeStyle(extraSmall ? variables.fontSizeExtraSmall : variables.fontSizeSmall)}
iconStyles={styles.mr0}
success
shouldUseXXSmallIcon={extraSmall}
textStyles={StyleUtils.getColorStyle(badgeTheme.textColor)}
/>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ function ActionCell({
<BadgeActionCell
action={action}
isLargeScreenWidth={isLargeScreenWidth}
isSelected={isSelected}
extraSmall={extraSmall}
shouldDisablePointerEvents={shouldDisablePointerEvents}
/>
);
Expand Down
26 changes: 7 additions & 19 deletions src/components/SelectionListWithSections/Search/StatusCell.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {useMemo} from 'react';
import {View} from 'react-native';
import Text from '@components/Text';
import StatusBadge from '@components/StatusBadge';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
Expand All @@ -25,29 +25,17 @@ function StatusCell({stateNum, statusNum, isPending}: StatusCellProps) {
const statusText = useMemo(() => getReportStatusTranslation({stateNum, statusNum, translate}), [stateNum, statusNum, translate]);
const reportStatusColorStyle = useMemo(() => getReportStatusColorStyle(theme, stateNum, statusNum), [theme, stateNum, statusNum]);

const backgroundColorStyle = useMemo(
() => ({
backgroundColor: reportStatusColorStyle?.backgroundColor,
}),
[reportStatusColorStyle?.backgroundColor],
);

const textColorStyle = useMemo(
() => ({
color: reportStatusColorStyle?.textColor,
}),
[reportStatusColorStyle?.textColor],
);

if (!statusText || !reportStatusColorStyle) {
return null;
}

return (
<View style={[styles.justifyContentCenter, styles.alignItemsCenter, isPending && styles.offlineFeedbackPending]}>
<View style={[styles.reportStatusContainer, backgroundColorStyle]}>
<Text style={[styles.reportStatusText, textColorStyle]}>{statusText}</Text>
</View>
<View style={[styles.w100, styles.justifyContentCenter, isPending && styles.offlineFeedbackPending]}>
<StatusBadge
text={statusText}
backgroundColor={reportStatusColorStyle.backgroundColor}
textColor={reportStatusColorStyle.textColor}
/>
</View>
);
}
Expand Down
Loading
Loading