I'm currently creating a React App using the Atomic Design methodology. I'm implementing a series of molecules to define a list row.
I currently have this IconTextItem
that implements an IconItem
import { Icon, IconProps } from '@components/icon';
import {
TopBottomText,
TopBottomTextProps,
} from '@ds/molecules/Text/TopBottomText';
import type { FunctionComponent } from 'react';
import React from 'react';
import { IconItem, IconItemProps } from '../IconItem';
export type IconTextItemProps = {
icon: IconProps;
onPress?(): void;
middleText?: TopBottomTextProps;
endText?: TopBottomTextProps;
endIcon?: IconProps;
containerStyle?: IconItemProps['containerStyle'];
};
export const IconTextItem: FunctionComponent<IconTextItemProps> = props => {
const { icon, middleText, endText, endIcon } = props;
return (
<IconItem
containerStyle={props.containerStyle}
onPress={props.onPress}
icon={icon}
middle={<TopBottomText {...middleText} />}
right={
<>
{endText && <TopBottomText {...endText} />}
{endIcon && <Icon {...endIcon} />}
</>
}
/>
);
};
This is the IconItem
component:
import React from 'react';
import { Icon, IconProps } from '@components/icon';
import type { FunctionComponent } from 'react';
import { BaseItem, BaseItemProps } from '../BaseItem';
export type IconItemProps = {
icon: IconProps;
onPress?(): void;
middle?: JSX.Element;
right?: JSX.Element;
containerStyle?: BaseItemProps['containerStyle'];
};
export const IconItem: FunctionComponent<IconItemProps> = props => {
const { icon, ...otherProps } = props;
return <BaseItem left={<Icon {...icon} />} {...otherProps} />;
};
Here's the BaseItem
import { Touchable } from '@components/buttons';
import { Flex, FlexProps } from '@ds/molecules/Layouts/utilities/Flex';
import type { FunctionComponent } from 'react';
import React from 'react';
export type BaseItemProps = {
onPress?(): void;
left?: JSX.Element;
middle?: JSX.Element;
right?: JSX.Element;
containerStyle?: FlexProps['style'];
};
export const BaseItem: FunctionComponent<BaseItemProps> = props => {
const { left, middle, right, onPress, containerStyle } = props;
const main = (
<Flex flexDirection="row" alignItems="center" style={containerStyle}>
{left && (
<Flex justifySelf="flex-left" mr="3x">
{left}
</Flex>
)}
{middle && (
<Flex justifySelf="flex-left" style={{ flex: 1 }}>
{middle}
</Flex>
)}
{right && (
<Flex style={{ alignItems: 'flex-end', flex: 1 }}>{right}</Flex>
)}
</Flex>
);
if (onPress) {
return <Touchable onPress={onPress}>{main}</Touchable>;
}
return main;
};
Now, I want to implement a variant of the IconTextItem
that will hold its icon
property as optional.
The problem is that both: IconItem
and IconTextItem
enforces the icon
property to be passed as required.
I don't think that lexing the requirement at the property will be a good idea, as I want it to be present for those cases.
This makes me think of the following two approaches:
Create an optional
OptionalIconItem
(need a better name) that will hold the icon as optional, and then wrap another component that passes the icon as required.Create a variant: one optional and the other required, leaving me the approach on #1 but everything is defined in a single component.
Which approach should I take, or is there a better way to approach this problem?