Skip to content

Commit

Permalink
Merge pull request #30579 from JKobrynski/migrateIconToTypeScript
Browse files Browse the repository at this point in the history
[TS Migration] Migrate Icon to TypeScript
  • Loading branch information
roryabraham authored Nov 10, 2023
2 parents 9aa6ae1 + 0d05be8 commit da1dda3
Show file tree
Hide file tree
Showing 18 changed files with 103 additions and 69 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion src/components/Icon/IconWrapperStyles/index.ios.js

This file was deleted.

7 changes: 7 additions & 0 deletions src/components/Icon/IconWrapperStyles/index.ios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import IconWrapperStyle from './types';

const style: IconWrapperStyle = {
top: 1,
};

export default style;
1 change: 0 additions & 1 deletion src/components/Icon/IconWrapperStyles/index.js

This file was deleted.

7 changes: 7 additions & 0 deletions src/components/Icon/IconWrapperStyles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import IconWrapperStyle from './types';

const style: IconWrapperStyle = {
top: 2,
};

export default style;
5 changes: 5 additions & 0 deletions src/components/Icon/IconWrapperStyles/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type IconWrapperStyle = {
top: number;
};

export default IconWrapperStyle;
File renamed without changes.
File renamed without changes.
14 changes: 0 additions & 14 deletions src/components/Icon/__mocks__/Expensicons.js

This file was deleted.

9 changes: 9 additions & 0 deletions src/components/Icon/__mocks__/Expensicons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const Expensicons = jest.requireActual('../Expensicons');

module.exports = Object.keys(Expensicons).reduce((prev, curr) => {
// We set the name of the anonymous mock function here so we can dynamically build the list of mocks and access the
// "name" property to use in accessibility hints for element querying
const fn = () => '';
Object.defineProperty(fn, 'name', {value: curr});
return {...prev, [curr]: fn};
}, {});
73 changes: 39 additions & 34 deletions src/components/Icon/index.js → src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,81 @@
import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import {View} from 'react-native';
import {StyleProp, View, ViewStyle} from 'react-native';
import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
import themeColors from '@styles/themes/default';
import variables from '@styles/variables';
import IconWrapperStyles from './IconWrapperStyles';

const propTypes = {
type SrcProps = {
width?: number;
height?: number;
fill?: string;
hovered?: string;
pressed?: string;
};

type IconProps = {
/** The asset to render. */
src: PropTypes.func.isRequired,
src: (props: SrcProps) => React.ReactNode;

/** The width of the icon. */
width: PropTypes.number,
width?: number;

/** The height of the icon. */
height: PropTypes.number,
height?: number;

/** The fill color for the icon. Can be hex, rgb, rgba, or valid react-native named color such as 'red' or 'blue'. */
fill: PropTypes.string,
fill?: string;

/** Is small icon */
small: PropTypes.bool,
small?: boolean;

/** Is inline icon */
inline: PropTypes.bool,
inline?: boolean;

/** Is icon hovered */
hovered: PropTypes.bool,
hovered?: boolean;

/** Is icon pressed */
pressed: PropTypes.bool,

// eslint-disable-next-line react/forbid-prop-types
additionalStyles: PropTypes.arrayOf(PropTypes.object),
};
pressed?: boolean;

const defaultProps = {
width: variables.iconSizeNormal,
height: variables.iconSizeNormal,
fill: themeColors.icon,
small: false,
inline: false,
additionalStyles: [],
hovered: false,
pressed: false,
/** Additional styles to add to the Icon */
additionalStyles?: StyleProp<ViewStyle>;
};

// We must use a class component to create an animatable component with the Animated API
// eslint-disable-next-line react/prefer-stateless-function
class Icon extends PureComponent {
class Icon extends PureComponent<IconProps> {
// eslint-disable-next-line react/static-property-placement
public static defaultProps = {
width: variables.iconSizeNormal,
height: variables.iconSizeNormal,
fill: themeColors.icon,
small: false,
inline: false,
additionalStyles: [],
hovered: false,
pressed: false,
};

render() {
const width = this.props.small ? variables.iconSizeSmall : this.props.width;
const height = this.props.small ? variables.iconSizeSmall : this.props.height;
const iconStyles = [StyleUtils.getWidthAndHeightStyle(width, height), IconWrapperStyles, styles.pAbsolute, ...this.props.additionalStyles];
const iconStyles = [StyleUtils.getWidthAndHeightStyle(width ?? 0, height), IconWrapperStyles, styles.pAbsolute, this.props.additionalStyles];

if (this.props.inline) {
return (
<View
testID={`${this.props.src.name} Icon`}
style={[StyleUtils.getWidthAndHeightStyle(width, height), styles.bgTransparent, styles.overflowVisible]}
style={[StyleUtils.getWidthAndHeightStyle(width ?? 0, height), styles.bgTransparent, styles.overflowVisible]}
>
<View style={iconStyles}>
<this.props.src
width={width}
height={height}
fill={this.props.fill}
hovered={this.props.hovered.toString()}
pressed={this.props.pressed.toString()}
hovered={this.props.hovered?.toString()}
pressed={this.props.pressed?.toString()}
/>
</View>
</View>
Expand All @@ -83,15 +91,12 @@ class Icon extends PureComponent {
width={width}
height={height}
fill={this.props.fill}
hovered={this.props.hovered.toString()}
pressed={this.props.pressed.toString()}
hovered={this.props.hovered?.toString()}
pressed={this.props.pressed?.toString()}
/>
</View>
);
}
}

Icon.propTypes = propTypes;
Icon.defaultProps = defaultProps;

export default Icon;
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import PropTypes from 'prop-types';
import * as React from 'react';
import Svg, {G, Path, Polygon} from 'react-native-svg';
import themeColors from '@styles/themes/default';

const propTypes = {
type LoungeAccessIconProps = {
/** The fill color for the icon. Can be hex, rgb, rgba, or valid react-native named color such as 'red' or 'blue'. */
fill: PropTypes.string,
fill?: string;

/** Is icon hovered */
hovered: PropTypes.string,
hovered?: string;

/** Is icon pressed */
pressed: PropTypes.string,
};
pressed?: string;

/** Icon's width */
width?: number;

const defaultProps = {
fill: themeColors.icon,
hovered: 'false',
pressed: 'false',
/** Icon's height */
height?: number;
};

function LoungeAccessIcon(props) {
function LoungeAccessIcon({fill = themeColors.icon, hovered = 'false', pressed = 'false', width, height}: LoungeAccessIconProps) {
return (
<Svg
id="Layer_1"
Expand All @@ -33,8 +32,11 @@ function LoungeAccessIcon(props) {
enableBackground: 'new 0 0 40 40',
}}
xmlSpace="preserve"
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
fill={fill}
hovered={hovered}
pressed={pressed}
width={width}
height={height}
>
<G>
<Path
Expand All @@ -44,13 +46,13 @@ function LoungeAccessIcon(props) {
</G>
<G>
<Path
fill={props.hovered === 'true' || props.pressed === 'true' ? props.fill : themeColors.starDefaultBG}
fill={hovered === 'true' || pressed === 'true' ? fill : themeColors.starDefaultBG}
className="st1"
d="M31,9.8c-0.1-0.2-0.2-0.4-0.5-0.4h-2.1l-0.8-2C27.4,7,27.1,7,27,7c-0.1,0-0.4,0-0.6,0.4l-0.8,1.9h-2.1 c-0.4,0-0.5,0.4-0.5,0.4c0,0.1-0.1,0.4,0.1,0.6l1.6,1.8l-0.6,1.9c-0.1,0.3,0.1,0.5,0.2,0.7c0.1,0,0.3,0.2,0.7,0.1l2-1.1l2,1.2 c0.3,0.2,0.6,0,0.7-0.1c0.1-0.1,0.3-0.3,0.2-0.7l-0.6-2l1.5-1.7C31,10.3,31,10,31,9.8z"
/>
<Polygon
className="st1"
points="28.5,7 28.5,7 28.5,7 "
className="st1"
/>
</G>
<G>
Expand All @@ -64,7 +66,4 @@ function LoungeAccessIcon(props) {
}

LoungeAccessIcon.displayName = 'LoungeAccessIcon';
LoungeAccessIcon.propTypes = propTypes;
LoungeAccessIcon.defaultProps = defaultProps;

export default LoungeAccessIcon;
2 changes: 1 addition & 1 deletion src/components/Pressable/PressableWithDelayToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function PressableWithDelayToggle(
<Icon
src={!isActive ? iconChecked : icon}
fill={StyleUtils.getIconFillColor(getButtonState(hovered, pressed, !isActive))}
style={iconStyles}
additionalStyles={iconStyles}
width={variables.iconSizeSmall}
height={variables.iconSizeSmall}
inline={inline}
Expand Down
17 changes: 17 additions & 0 deletions src/types/modules/react-native-svg.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {CommonPathProps as BaseCommonPathProps, SvgProps as BaseSvgProps} from 'react-native-svg';

declare module 'react-native-svg' {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface SvgProps extends BaseSvgProps {
xmlns?: string;
xmlnsXlink?: string;
xmlSpace?: string;
hovered?: string;
pressed?: string;
}

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface CommonPathProps extends BaseCommonPathProps {
className?: string;
}
}
1 change: 1 addition & 0 deletions src/types/modules/react-native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ declare module 'react-native' {
// Exclusive to react-native-web, "pointerEvents" already included on RN
animationKeyframes?: string | Record<string, ViewStyle>;
writingDirection?: 'auto' | 'ltr' | 'rtl';
enableBackground?: string;
}

interface ViewStyle extends WebStyle {}
Expand Down

0 comments on commit da1dda3

Please sign in to comment.