Skip to content

Commit

Permalink
Discriminative union for icon types
Browse files Browse the repository at this point in the history
  • Loading branch information
MaciejSWM committed Dec 14, 2023
1 parent 1ed677c commit bbe82dc
Showing 1 changed file with 119 additions and 106 deletions.
225 changes: 119 additions & 106 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,165 +46,174 @@ type UnresponsiveProps = {
interactive: false;
};

type MenuItemProps = (ResponsiveProps | UnresponsiveProps) & {
/** Text to be shown as badge near the right end. */
badgeText?: string;
type IconProps = {
/** Flag to choose between avatar image or an icon */
iconType: typeof CONST.ICON_TYPE_ICON;

/** Used to apply offline styles to child text components */
style?: ViewStyle;
/** Icon to display on the left side of component */
icon: (props: SrcProps) => ReactNode;
};

/** Any additional styles to apply */
wrapperStyle?: StyleProp<ViewStyle>;
type AvatarProps = {
iconType: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;

/** Any additional styles to apply on the outer element */
containerStyle?: StyleProp<ViewStyle>;
icon: AvatarSource;
};

/** Used to apply styles specifically to the title */
titleStyle?: ViewStyle;
type MenuItemProps = (ResponsiveProps | UnresponsiveProps) &
(IconProps | AvatarProps) & {
/** Text to be shown as badge near the right end. */
badgeText?: string;

/** Any adjustments to style when menu item is hovered or pressed */
hoverAndPressStyle: StyleProp<AnimatedStyle<ViewStyle>>;
/** Used to apply offline styles to child text components */
style?: ViewStyle;

descriptionTextStyle?: StyleProp<ViewStyle>;
/** Any additional styles to apply */
wrapperStyle?: StyleProp<ViewStyle>;

/** Icon to display on the left side of component */
icon?: ((props: SrcProps) => ReactNode) | AvatarSource;
/** Any additional styles to apply on the outer element */
containerStyle?: StyleProp<ViewStyle>;

/** The fill color to pass into the icon. */
iconFill?: string;
/** Used to apply styles specifically to the title */
titleStyle?: ViewStyle;

/** Secondary icon to display on the left side of component, right of the icon */
secondaryIcon?: (props: SrcProps) => React.ReactNode;
/** Any adjustments to style when menu item is hovered or pressed */
hoverAndPressStyle: StyleProp<AnimatedStyle<ViewStyle>>;

/** The fill color to pass into the secondary icon. */
secondaryIconFill?: string;
descriptionTextStyle?: StyleProp<ViewStyle>;

/** Flag to choose between avatar image or an icon */
iconType?: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_ICON | typeof CONST.ICON_TYPE_WORKSPACE;
/** The fill color to pass into the icon. */
iconFill?: string;

/** Icon Width */
iconWidth?: number;
/** Secondary icon to display on the left side of component, right of the icon */
secondaryIcon?: (props: SrcProps) => React.ReactNode;

/** Icon Height */
iconHeight?: number;
/** The fill color to pass into the secondary icon. */
secondaryIconFill?: string;

/** Any additional styles to pass to the icon container. */
iconStyles?: StyleProp<ViewStyle>;
/** Icon Width */
iconWidth?: number;

/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon?: FC<SvgProps>;
/** Icon Height */
iconHeight?: number;

/** An icon to display under the main item */
furtherDetailsIcon?: (props: SrcProps) => ReactNode;
/** Any additional styles to pass to the icon container. */
iconStyles?: StyleProp<ViewStyle>;

/** Boolean whether to display the title right icon */
shouldShowTitleIcon?: boolean;
/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon?: FC<SvgProps>;

/** Icon to display at right side of title */
titleIcon?: (props: SrcProps) => ReactNode;
/** An icon to display under the main item */
furtherDetailsIcon?: (props: SrcProps) => ReactNode;

/** Boolean whether to display the right icon */
shouldShowRightIcon?: boolean;
/** Boolean whether to display the title right icon */
shouldShowTitleIcon?: boolean;

/** Overrides the icon for shouldShowRightIcon */
iconRight?: (props: SrcProps) => ReactNode;
/** Icon to display at right side of title */
titleIcon?: (props: SrcProps) => ReactNode;

/** Should render component on the right */
shouldShowRightComponent?: boolean;
/** Boolean whether to display the right icon */
shouldShowRightIcon?: boolean;

/** Component to be displayed on the right */
rightComponent?: ReactNode;
/** Overrides the icon for shouldShowRightIcon */
iconRight?: (props: SrcProps) => ReactNode;

/** A description text to show under the title */
description?: string;
/** Should render component on the right */
shouldShowRightComponent?: boolean;

/** Should the description be shown above the title (instead of the other way around) */
shouldShowDescriptionOnTop?: boolean;
/** Component to be displayed on the right */
rightComponent?: ReactNode;

/** Error to display below the title */
error?: string;
/** A description text to show under the title */
description?: string;

/** Error to display at the bottom of the component */
errorText?: string;
/** Should the description be shown above the title (instead of the other way around) */
shouldShowDescriptionOnTop?: boolean;

/** A boolean flag that gives the icon a green fill if true */
success?: boolean;
/** Error to display below the title */
error?: string;

/** Whether item is focused or active */
focused?: boolean;
/** Error to display at the bottom of the component */
errorText?: string;

/** Should we disable this menu item? */
disabled?: boolean;
/** A boolean flag that gives the icon a green fill if true */
success?: boolean;

/** Text that appears above the title */
label?: string;
/** Whether item is focused or active */
focused?: boolean;

/** Label to be displayed on the right */
rightLabel?: string;
/** Should we disable this menu item? */
disabled?: boolean;

/** Text to display for the item */
title?: string;
/** Text that appears above the title */
label?: string;

/** A right-aligned subtitle for this menu option */
subtitle?: string | number;
/** Label to be displayed on the right */
rightLabel?: string;

/** Should the title show with normal font weight (not bold) */
shouldShowBasicTitle?: boolean;
/** Text to display for the item */
title?: string;

/** Should we make this selectable with a checkbox */
shouldShowSelectedState?: boolean;
/** A right-aligned subtitle for this menu option */
subtitle?: string | number;

/** Whether this item is selected */
isSelected?: boolean;
/** Should the title show with normal font weight (not bold) */
shouldShowBasicTitle?: boolean;

/** Prop to identify if we should load avatars vertically instead of diagonally */
shouldStackHorizontally: boolean;
/** Should we make this selectable with a checkbox */
shouldShowSelectedState?: boolean;

/** Prop to represent the size of the avatar images to be shown */
avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];
/** Whether this item is selected */
isSelected?: boolean;

/** Avatars to show on the right of the menu item */
floatRightAvatars?: IconType[];
/** Prop to identify if we should load avatars vertically instead of diagonally */
shouldStackHorizontally: boolean;

/** Prop to represent the size of the float right avatar images to be shown */
floatRightAvatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];
/** Prop to represent the size of the avatar images to be shown */
avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];

viewMode?: (typeof CONST.OPTION_MODE)[keyof typeof CONST.OPTION_MODE];
/** Avatars to show on the right of the menu item */
floatRightAvatars?: IconType[];

numberOfLinesTitle?: number;
/** Prop to represent the size of the float right avatar images to be shown */
floatRightAvatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];

/** Whether we should use small avatar subscript sizing the for menu item */
isSmallAvatarSubscriptMenu?: boolean;
viewMode?: (typeof CONST.OPTION_MODE)[keyof typeof CONST.OPTION_MODE];

/** The type of brick road indicator to show. */
brickRoadIndicator?: (typeof CONST.BRICK_ROAD_INDICATOR_STATUS)[keyof typeof CONST.BRICK_ROAD_INDICATOR_STATUS];
numberOfLinesTitle?: number;

/** Should render the content in HTML format */
shouldRenderAsHTML?: boolean;
/** Whether we should use small avatar subscript sizing the for menu item */
isSmallAvatarSubscriptMenu?: boolean;

/** Should we grey out the menu item when it is disabled? */
shouldGreyOutWhenDisabled?: boolean;
/** The type of brick road indicator to show. */
brickRoadIndicator?: (typeof CONST.BRICK_ROAD_INDICATOR_STATUS)[keyof typeof CONST.BRICK_ROAD_INDICATOR_STATUS];

/** The action accept for anonymous user or not */
isAnonymousAction?: boolean;
/** Should render the content in HTML format */
shouldRenderAsHTML?: boolean;

/** Flag to indicate whether or not text selection should be disabled from long-pressing the menu item. */
shouldBlockSelection?: boolean;
/** Should we grey out the menu item when it is disabled? */
shouldGreyOutWhenDisabled?: boolean;

shouldParseTitle?: false;
/** The action accept for anonymous user or not */
isAnonymousAction?: boolean;

/** Should check anonymous user in onPress function */
shouldCheckActionAllowedOnPress?: boolean;
/** Flag to indicate whether or not text selection should be disabled from long-pressing the menu item. */
shouldBlockSelection?: boolean;

/** Text to display under the main item */
furtherDetails?: string;
shouldParseTitle?: false;

/** The function that should be called when this component is LongPressed or right-clicked. */
onSecondaryInteraction: () => void;
/** Should check anonymous user in onPress function */
shouldCheckActionAllowedOnPress?: boolean;

/** Array of objects that map display names to their corresponding tooltip */
titleWithTooltips: DisplayNameWithTooltip[];
};
/** Text to display under the main item */
furtherDetails?: string;

/** The function that should be called when this component is LongPressed or right-clicked. */
onSecondaryInteraction: () => void;

/** Array of objects that map display names to their corresponding tooltip */
titleWithTooltips: DisplayNameWithTooltip[];
};

function MenuItem(
{
Expand Down Expand Up @@ -414,6 +423,10 @@ function MenuItem(
}
/>
)}
</View>
)}
{Boolean(icon) && typeof icon !== 'function' && (
<View>
{iconType === CONST.ICON_TYPE_WORKSPACE && (
<Avatar
imageStyles={[styles.alignSelfCenter]}
Expand Down

0 comments on commit bbe82dc

Please sign in to comment.