Skip to content

Commit

Permalink
Merge pull request #3 from Georepublic/update-repo-link
Browse files Browse the repository at this point in the history
Fix path url
  • Loading branch information
chansuke authored Oct 16, 2020
2 parents a8e0a41 + bfdd5d8 commit 1cdc1b9
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 5 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
artifacts/
dist/

### Node ###
# Logs
Expand Down
70 changes: 70 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*!
* React Native Autolink
*
* Copyright 2016-2020 Josh Swan
* Released under the MIT license
* https://github.com/joshswan/react-native-autolink/blob/master/LICENSE
*/
import React, { PureComponent, ReactNode } from 'react';
import { Match } from 'autolinker/dist/es2015';
import { StyleProp, Text, TextStyle, TextProps } from 'react-native';
import { PropsOf } from './types';
interface AutolinkProps<C extends React.ComponentType = React.ComponentType> {
component?: C;
email?: boolean;
hashtag?: false | 'facebook' | 'instagram' | 'twitter';
latlng?: boolean;
linkProps?: TextProps;
linkStyle?: StyleProp<TextStyle>;
mention?: false | 'instagram' | 'soundcloud' | 'twitter';
onPress?: (url: string, match: Match) => void;
onLongPress?: (url: string, match: Match) => void;
phone?: boolean | 'text' | 'sms';
renderLink?: (text: string, match: Match, index: number) => React.ReactNode;
renderText?: (text: string, index: number) => React.ReactNode;
showAlert?: boolean;
stripPrefix?: boolean;
stripTrailingSlash?: boolean;
text: string;
textProps?: TextProps;
truncate?: number;
truncateChars?: string;
truncateLocation?: 'end' | 'middle' | 'smart';
url?: boolean | {
schemeMatches?: boolean;
wwwMatches?: boolean;
tldMatches?: boolean;
};
webFallback?: boolean;
}
declare type Props<C extends React.ComponentType> = AutolinkProps<C> & Omit<PropsOf<C>, keyof AutolinkProps>;
export default class Autolink<C extends React.ComponentType = typeof Text> extends PureComponent<Props<C>> {
static truncate(text: string, { truncate, truncateChars, truncateLocation, }?: {
truncate?: number | undefined;
truncateChars?: string | undefined;
truncateLocation?: string | undefined;
}): string;
static defaultProps: {
email: boolean;
hashtag: boolean;
latlng: boolean;
linkProps: {};
mention: boolean;
phone: boolean;
showAlert: boolean;
stripPrefix: boolean;
stripTrailingSlash: boolean;
textProps: {};
truncate: number;
truncateChars: string;
truncateLocation: string;
url: boolean;
webFallback: boolean;
};
onPress(match: Match, alertShown?: boolean): void;
onLongPress(match: Match): void;
getUrl(match: Match): string[];
renderLink(text: string, match: Match, index: number, textProps?: Partial<TextProps>): ReactNode;
render(): ReactNode;
}
export {};
219 changes: 219 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/*!
* React Native Autolink
*
* Copyright 2016-2020 Josh Swan
* Released under the MIT license
* https://github.com/joshswan/react-native-autolink/blob/master/LICENSE
*/
import React, { PureComponent, createElement } from 'react';
import { Autolinker, AnchorTagBuilder, } from 'autolinker/dist/es2015';
import { Alert, Linking, Platform, StyleSheet, Text, } from 'react-native';
import * as Truncate from './truncate';
import { Matchers } from './matchers';
const tagBuilder = new AnchorTagBuilder();
const styles = StyleSheet.create({
link: {
color: '#0E7AFE',
},
});
export default class Autolink extends PureComponent {
static truncate(text, { truncate = 32, truncateChars = '..', truncateLocation = 'smart', } = {}) {
let fn;
switch (truncateLocation) {
case 'end':
fn = Truncate.end;
break;
case 'middle':
fn = Truncate.middle;
break;
default:
fn = Truncate.smart;
}
return fn(text, truncate, truncateChars);
}
onPress(match, alertShown) {
const { onPress, showAlert, webFallback, } = this.props;
// Check if alert needs to be shown
if (showAlert && !alertShown) {
Alert.alert('Leaving App', 'Do you want to continue?', [
{ text: 'Cancel', style: 'cancel' },
{ text: 'OK', onPress: () => this.onPress(match, true) },
]);
return;
}
// Get url(s) for match
const [url, fallback,] = this.getUrl(match);
// Call custom onPress handler or open link/fallback
if (onPress) {
onPress(url, match);
}
else if (webFallback) {
Linking.canOpenURL(url).then((supported) => {
Linking.openURL(!supported && fallback ? fallback : url);
});
}
else {
Linking.openURL(url);
}
}
onLongPress(match) {
const { onLongPress } = this.props;
if (onLongPress) {
// Get url for match
const [url] = this.getUrl(match);
onLongPress(url, match);
}
}
getUrl(match) {
const { hashtag, mention, phone } = this.props;
const type = match.getType();
switch (type) {
case 'email': {
return [`mailto:${encodeURIComponent(match.getEmail())}`];
}
case 'hashtag': {
const tag = encodeURIComponent(match.getHashtag());
switch (hashtag) {
case 'facebook':
return [`fb://hashtag/${tag}`, `https://www.facebook.com/hashtag/${tag}`];
case 'instagram':
return [`instagram://tag?name=${tag}`, `https://www.instagram.com/explore/tags/${tag}/`];
case 'twitter':
return [`twitter://search?query=%23${tag}`, `https://twitter.com/hashtag/${tag}`];
default:
return [match.getMatchedText()];
}
}
case 'latlng': {
const latlng = match.getLatLng();
const query = latlng.replace(/\s/g, '');
return [Platform.OS === 'ios' ? `http://maps.apple.com/?q=${encodeURIComponent(latlng)}&ll=${query}` : `https://www.google.com/maps/search/?api=1&query=${query}`];
}
case 'mention': {
const username = match.getMention();
switch (mention) {
case 'instagram':
return [`instagram://user?username=${username}`, `https://www.instagram.com/${username}/`];
case 'soundcloud':
return [`https://soundcloud.com/${username}`];
case 'twitter':
return [`twitter://user?screen_name=${username}`, `https://twitter.com/${username}`];
default:
return [match.getMatchedText()];
}
}
case 'phone': {
const number = match.getNumber();
switch (phone) {
case 'sms':
case 'text':
return [`sms:${number}`];
default:
return [`tel:${number}`];
}
}
case 'url': {
return [match.getAnchorHref()];
}
default: {
return [match.getMatchedText()];
}
}
}
renderLink(text, match, index, textProps = {}) {
const { truncate, linkStyle } = this.props;
const truncated = truncate ? Autolink.truncate(text, this.props) : text;
return (React.createElement(Text, Object.assign({ style: linkStyle || styles.link, onPress: () => this.onPress(match), onLongPress: () => this.onLongPress(match) }, textProps, { key: index }), truncated));
}
render() {
const { children, component = Text, email, hashtag, latlng, linkProps, linkStyle, mention, onPress, onLongPress, phone, renderLink, renderText, showAlert, stripPrefix, stripTrailingSlash, text, textProps, truncate, truncateChars, truncateLocation, url, webFallback, ...other } = this.props;
// Creates a token with a random UID that should not be guessable or
// conflict with other parts of the string.
const uid = Math.floor(Math.random() * 0x10000000000).toString(16);
const tokenRegexp = new RegExp(`(@__ELEMENT-${uid}-\\d+__@)`, 'g');
const generateToken = (() => {
let counter = 0;
return () => `@__ELEMENT-${uid}-${counter++}__@`; // eslint-disable-line no-plusplus
})();
const matches = {};
let linkedText;
try {
linkedText = Autolinker.link(text || '', {
email,
hashtag,
mention,
phone: !!phone,
urls: url,
stripPrefix,
stripTrailingSlash,
replaceFn: (match) => {
const token = generateToken();
matches[token] = match;
return token;
},
});
// Custom matchers
Matchers.forEach((matcher) => {
// eslint-disable-next-line react/destructuring-assignment
if (this.props[matcher.id]) {
linkedText = linkedText.replace(matcher.regex, (...args) => {
const token = generateToken();
const matchedText = args[0];
matches[token] = new matcher.Match({
tagBuilder,
matchedText,
offset: args[args.length - 2],
[matcher.id]: matchedText,
});
return token;
});
}
});
}
catch (e) {
console.warn(e); // eslint-disable-line no-console
return null;
}
const nodes = linkedText
.split(tokenRegexp)
.filter((part) => !!part)
.map((part, index) => {
var _a;
const match = matches[part];
switch ((_a = match) === null || _a === void 0 ? void 0 : _a.getType()) {
case 'email':
case 'hashtag':
case 'latlng':
case 'mention':
case 'phone':
case 'url':
return renderLink
? renderLink(match.getAnchorText(), match, index)
: this.renderLink(match.getAnchorText(), match, index, linkProps);
default:
return renderText
? renderText(part, index)
// eslint-disable-next-line react/jsx-props-no-spreading, react/no-array-index-key
: React.createElement(Text, Object.assign({}, textProps, { key: index }), part);
}
});
return createElement(component, other, ...nodes);
}
}
Autolink.defaultProps = {
email: true,
hashtag: false,
latlng: false,
linkProps: {},
mention: false,
phone: true,
showAlert: false,
stripPrefix: true,
stripTrailingSlash: true,
textProps: {},
truncate: 32,
truncateChars: '..',
truncateLocation: 'smart',
url: true,
webFallback: Platform.OS !== 'ios',
};
32 changes: 32 additions & 0 deletions dist/matchers.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*!
* React Native Autolink
*
* Copyright 2016-2020 Josh Swan
* Released under the MIT license
* https://github.com/joshswan/react-native-autolink/blob/master/LICENSE
*/
import { Match, MatchConfig } from 'autolinker/dist/es2015';
export interface LatLngMatchConfig extends MatchConfig {
latlng: string;
}
export declare class LatLngMatch extends Match {
private latlng;
constructor(cfg: LatLngMatchConfig);
getType(): string;
getLatLng(): string;
getAnchorHref(): string;
getAnchorText(): string;
}
export declare const CustomMatchers: {
latlng: {
id: string;
regex: RegExp;
Match: typeof LatLngMatch;
};
};
export declare type MatcherId = keyof typeof CustomMatchers;
export declare const Matchers: {
id: string;
regex: RegExp;
Match: typeof LatLngMatch;
}[];
35 changes: 35 additions & 0 deletions dist/matchers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*!
* React Native Autolink
*
* Copyright 2016-2020 Josh Swan
* Released under the MIT license
* https://github.com/joshswan/react-native-autolink/blob/master/LICENSE
*/
import { Match } from 'autolinker/dist/es2015';
export class LatLngMatch extends Match {
constructor(cfg) {
super(cfg);
this.latlng = cfg.latlng;
}
getType() {
return 'latlng';
}
getLatLng() {
return this.latlng;
}
getAnchorHref() {
return this.latlng;
}
getAnchorText() {
return this.latlng;
}
}
export const CustomMatchers = {
// LatLng
latlng: {
id: 'latlng',
regex: /[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)/g,
Match: LatLngMatch,
},
};
export const Matchers = Object.keys(CustomMatchers).map((key) => CustomMatchers[key]);
11 changes: 11 additions & 0 deletions dist/truncate.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*!
* React Native Autolink
*
* Copyright 2016-2020 Josh Swan
* Released under the MIT license
* https://github.com/joshswan/react-native-autolink/blob/master/LICENSE
*/
import { truncateEnd as end } from 'autolinker/dist/es2015/truncate/truncate-end';
import { truncateMiddle as middle } from 'autolinker/dist/es2015/truncate/truncate-middle';
import { truncateSmart as smart } from 'autolinker/dist/es2015/truncate/truncate-smart';
export { end, middle, smart, };
11 changes: 11 additions & 0 deletions dist/truncate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*!
* React Native Autolink
*
* Copyright 2016-2020 Josh Swan
* Released under the MIT license
* https://github.com/joshswan/react-native-autolink/blob/master/LICENSE
*/
import { truncateEnd as end } from 'autolinker/dist/es2015/truncate/truncate-end';
import { truncateMiddle as middle } from 'autolinker/dist/es2015/truncate/truncate-middle';
import { truncateSmart as smart } from 'autolinker/dist/es2015/truncate/truncate-smart';
export { end, middle, smart, };
2 changes: 2 additions & 0 deletions dist/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="react" />
export declare type PropsOf<E extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>> = JSX.LibraryManagedAttributes<E, React.ComponentPropsWithRef<E>>;
Empty file added dist/types.js
Empty file.
Loading

0 comments on commit 1cdc1b9

Please sign in to comment.