Example:
<AutoLink linkStyle={ styles.textLink } text='this is a phone number 9999999999' />
// @flow | |
import React from 'react'; | |
import { Linking, Text } from 'react-native'; | |
import { parsePhoneNumber, type TextChild } from 'utils/strings'; | |
type Props = { | |
linkStyle: PassedStyle, | |
text: string, | |
}; | |
class AutoLink extends React.PureComponent<Props> { | |
render(): Text { | |
const { text } = this.props; | |
return ( | |
<Text { ...this.props }> | |
{typeof text !== 'string' ? text : this.getParsedText()} | |
</Text> | |
); | |
} | |
getParsedText(): Array<Text> { | |
const { linkStyle, text } = this.props; | |
const parsed = parsePhoneNumber({ | |
text, | |
linkProps: { | |
onPress: this.handlePress, | |
style: linkStyle, | |
}, | |
}); | |
return parsed.map((props: TextChild, index: number): Text => ( | |
<Text key={ `parsedText-${index}` } { ...props } /> | |
)); | |
} | |
handlePress = (number: string) => { | |
Linking.openURL(`tel:${number}`); | |
}; | |
} | |
export default AutoLink; |
Example:
<AutoLink linkStyle={ styles.textLink } text='this is a phone number 9999999999' />
// @flow | |
import { type TextProps } from 'react-native'; | |
const textWithPhoneNumberRegex = /([\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,7})/; | |
export type TextChild = { | |
onPress?: Function, | |
} & TextProps; | |
export const parsePhoneNumber = ({ | |
linkProps: { onPress, ...otherLinkProps } = {}, | |
text, | |
}: { | |
linkProps: TextChild, | |
text: string, | |
}): Array<TextChild> => { | |
const parseFraction = ( | |
textLeft: string, | |
previousFraction: ?Array<TextChild>, | |
): Array<TextChild> => { | |
const matches = textWithPhoneNumberRegex.exec(textLeft); | |
const fraction = previousFraction || []; | |
if (!matches) { | |
return [...fraction, { children: textLeft }].filter( | |
(child: TextChild): boolean => !!child.children, | |
); | |
} | |
fraction.push({ children: textLeft.substr(0, matches.index) }); | |
fraction.push({ | |
children: matches[0], | |
onPress: (): void => onPress && onPress(matches[0]), | |
...otherLinkProps, | |
}); | |
return parseFraction( | |
textLeft.substr(matches.index + matches[0].length), | |
fraction, | |
); | |
}; | |
return parseFraction(text); | |
}; |
import { parsePhoneNumber } from './strings'; | |
describe('parsePhoneNumber', () => { | |
const linkProps = { | |
onPress: jest.fn(), | |
otherProp: 'test', | |
}; | |
const receivedLinkProps = { | |
...linkProps, | |
onPress: expect.any(Function), | |
}; | |
test('validates messages', () => { | |
expect(parsePhoneNumber({ text: 'Lorem ipsum' })).toEqual([ | |
{ children: 'Lorem ipsum' }, | |
]); | |
expect( | |
parsePhoneNumber({ | |
text: 'this is a normal number 99999', | |
linkProps, | |
}), | |
).toEqual([{ children: 'this is a normal number 99999' }]); | |
expect( | |
parsePhoneNumber({ | |
text: 'but this is a phone number 9999999999', | |
linkProps, | |
}), | |
).toEqual([ | |
{ children: 'but this is a phone number ' }, | |
{ children: '9999999999', ...receivedLinkProps }, | |
]); | |
expect( | |
parsePhoneNumber({ | |
text: '929-222-3456 92921346544 +556192334456', | |
linkProps, | |
}), | |
).toEqual([ | |
{ children: '929-222-3456', ...receivedLinkProps }, | |
{ children: ' ' }, | |
{ children: '92921346544', ...receivedLinkProps }, | |
{ children: ' ' }, | |
{ children: '+556192334456', ...receivedLinkProps }, | |
]); | |
}); | |
}); |