Skip to content

Commit

Permalink
Typescript rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
mxck committed Aug 19, 2021
1 parent 8770dd0 commit c2c1e50
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 108 deletions.
7 changes: 5 additions & 2 deletions package.json
Expand Up @@ -15,14 +15,17 @@
"author": "Maksim Milyutin <mmxckk@gmail.com> (https://github.com/mxck)",
"license": "MIT",
"scripts": {
"build": "tsc",
"build": "rimraf dist && tsc",
"prepublishOnly": "npm run build",
"prettify": "prettier --write 'src/**/*.js' && eslint 'src/**/*.js'"
"prettify": "prettier --write 'src/**/*.(js|tsx|ts)' && eslint 'src/**/*.{js,ts,tsx}'"
},
"devDependencies": {
"@react-native-community/eslint-config": "~3.0.0",
"@types/react": "^17.0.19",
"@types/react-native": "^0.64.13",
"eslint": "~7.32.0",
"prettier": "~2.3.0",
"rimraf": "~3.0.0",
"typescript": "~4.3.5"
},
"peerDependencies": {
Expand Down
71 changes: 46 additions & 25 deletions src/Menu.js → src/Menu.tsx
Expand Up @@ -5,31 +5,58 @@ import {
Dimensions,
Easing,
I18nManager,
LayoutChangeEvent,
Modal,
Platform,
StatusBar,
StyleSheet,
TouchableWithoutFeedback,
View,
ViewStyle,
} from 'react-native';

const STATES = {
HIDDEN: 'HIDDEN',
ANIMATING: 'ANIMATING',
SHOWN: 'SHOWN',
};
export interface MenuProps {
children?: React.ReactNode;
button?: React.ReactNode;
style?: ViewStyle;
onHidden?(): void;
animationDuration?: number;
testID?: string;
}

enum States {
Hidden,
Animating,
Shown,
}

interface State {
buttonHeight: number;
buttonWidth: number;
left: number;
menuHeight: number;
menuSizeAnimation: Animated.ValueXY;
menuState: States;
menuWidth: number;
opacityAnimation: Animated.Value;
top: number;
}

const EASING = Easing.bezier(0.4, 0, 0.2, 1);
const SCREEN_INDENT = 8;

class Menu extends React.Component {
_container = null;
export class Menu extends React.Component<MenuProps, State> {
_container: View | null = null;

constructor(props) {
static defaultProps = {
animationDuration: 21,
};

constructor(props: MenuProps) {
super(props);

this.state = {
menuState: STATES.HIDDEN,
menuState: States.Hidden,

top: 0,
left: 0,
Expand All @@ -45,21 +72,21 @@ class Menu extends React.Component {
};
}

_setContainerRef = (ref) => {
_setContainerRef = (ref: View) => {
this._container = ref;
};

// Start menu animation
_onMenuLayout = (e) => {
if (this.state.menuState === STATES.ANIMATING) {
_onMenuLayout = (e: LayoutChangeEvent) => {
if (this.state.menuState === States.Animating) {
return;
}

const { width, height } = e.nativeEvent.layout;

this.setState(
{
menuState: STATES.ANIMATING,
menuState: States.Animating,
menuWidth: width,
menuHeight: height,
},
Expand All @@ -83,18 +110,18 @@ class Menu extends React.Component {
};

show = () => {
this._container.measureInWindow((left, top, buttonWidth, buttonHeight) => {
this._container?.measureInWindow((left, top, buttonWidth, buttonHeight) => {
this.setState({
buttonHeight,
buttonWidth,
left,
menuState: STATES.SHOWN,
menuState: States.Shown,
top,
});
});
};

hide = (onHidden) => {
hide = (onHidden?: () => void) => {
Animated.timing(this.state.opacityAnimation, {
toValue: 0,
duration: this.props.animationDuration,
Expand All @@ -104,7 +131,7 @@ class Menu extends React.Component {
// Reset state
this.setState(
{
menuState: STATES.HIDDEN,
menuState: States.Hidden,
menuSizeAnimation: new Animated.ValueXY({ x: 0, y: 0 }),
opacityAnimation: new Animated.Value(0),
},
Expand Down Expand Up @@ -186,8 +213,8 @@ class Menu extends React.Component {
};

const { menuState } = this.state;
const animationStarted = menuState === STATES.ANIMATING;
const modalVisible = menuState === STATES.SHOWN || animationStarted;
const animationStarted = menuState === States.Animating;
const modalVisible = menuState === States.Shown || animationStarted;

const { testID, button, style, children } = this.props;

Expand Down Expand Up @@ -225,10 +252,6 @@ class Menu extends React.Component {
}
}

Menu.defaultProps = {
animationDuration: 300,
};

const styles = StyleSheet.create({
shadowMenuContainer: {
position: 'absolute',
Expand All @@ -253,5 +276,3 @@ const styles = StyleSheet.create({
overflow: 'hidden',
},
});

export default Menu;
12 changes: 5 additions & 7 deletions src/MenuDivider.js → src/MenuDivider.tsx
Expand Up @@ -2,19 +2,17 @@ import React from 'react';

import { StyleSheet, View } from 'react-native';

function MenuDivider({ color }) {
return <View style={[styles.divider, { borderBottomColor: color }]} />;
export interface MenuDividerProps {
color?: string;
}

MenuDivider.defaultProps = {
color: 'rgba(0,0,0,0.12)',
};
export function MenuDivider({ color = 'rgba(0,0,0,0.12)' }: MenuDividerProps) {
return <View style={[styles.divider, { borderBottomColor: color }]} />;
}

const styles = StyleSheet.create({
divider: {
flex: 1,
borderBottomWidth: StyleSheet.hairlineWidth,
},
});

export default MenuDivider;
69 changes: 0 additions & 69 deletions src/MenuItem.js

This file was deleted.

62 changes: 62 additions & 0 deletions src/MenuItem.tsx
@@ -0,0 +1,62 @@
import React from 'react';

import {
Platform,
Pressable,
PressableProps,
StyleSheet,
Text,
TextProps,
TextStyle,
View,
ViewStyle,
} from 'react-native';

export type MenuItemProps = {
children?: React.ReactNode;
disabled?: boolean;
disabledTextColor?: string;
ellipsizeMode?: TextProps['ellipsizeMode'];
style?: ViewStyle;
textStyle?: TextStyle;
} & PressableProps;

export function MenuItem({
children,
disabled = false,
disabledTextColor = '#bdbdbd',
ellipsizeMode = Platform.OS === 'ios' ? 'clip' : 'tail',
onPress,
style,
textStyle,
...props
}: MenuItemProps) {
return (
<Pressable disabled={disabled} onPress={onPress} {...props}>
<View style={[styles.container, style]}>
<Text
ellipsizeMode={ellipsizeMode}
numberOfLines={1}
style={[styles.title, disabled && { color: disabledTextColor }, textStyle]}
>
{children}
</Text>
</View>
</Pressable>
);
}

const styles = StyleSheet.create({
container: {
height: 48,
justifyContent: 'center',
maxWidth: 248,
minWidth: 124,
},
title: {
fontSize: 14,
fontWeight: '400',
paddingHorizontal: 16,
textAlign: 'left',
},
});
4 changes: 0 additions & 4 deletions src/index.js

This file was deleted.

7 changes: 7 additions & 0 deletions src/index.ts
@@ -0,0 +1,7 @@
export { Menu } from './Menu';
export { MenuDivider } from './MenuDivider';
export { MenuItem } from './MenuItem';

export type { MenuDividerProps } from './MenuDivider';
export type { MenuItemProps } from './MenuItem';
export type { MenuProps } from './Menu';
33 changes: 32 additions & 1 deletion yarn.lock
Expand Up @@ -185,6 +185,32 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==

"@types/prop-types@*":
version "15.7.4"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==

"@types/react-native@^0.64.13":
version "0.64.13"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.64.13.tgz#9e57b85631380b75979a09f5a97e1884299e8d5a"
integrity sha512-QSOBN6m3TKBPFAcDhuFItDQtw1Fo1/FKDTHGeyeTwBXd3bu0V9s+oHEhntHN7PUK5dAOYFWsnO0wynWwS/KRxQ==
dependencies:
"@types/react" "*"

"@types/react@*", "@types/react@^17.0.19":
version "17.0.19"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.19.tgz#8f2a85e8180a43b57966b237d26a29481dacc991"
integrity sha512-sX1HisdB1/ZESixMTGnMxH9TDe8Sk709734fEQZzCV/4lSu9kJCPbo2PbTRoZM+53Pp0P10hYVyReUueGwUi4A==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==

"@typescript-eslint/eslint-plugin@^4.22.1":
version "4.29.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz#f54dc0a32b8f61c6024ab8755da05363b733838d"
Expand Down Expand Up @@ -446,6 +472,11 @@ cross-spawn@^7.0.2:
shebang-command "^2.0.0"
which "^2.0.1"

csstype@^3.0.2:
version "3.0.8"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==

debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
version "4.3.2"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
Expand Down Expand Up @@ -1349,7 +1380,7 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==

rimraf@^3.0.2:
rimraf@^3.0.2, rimraf@~3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
Expand Down

0 comments on commit c2c1e50

Please sign in to comment.