├── .gitattributes
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── index.js
└── package.json
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # OSX
3 | #
4 | .DS_Store
5 |
6 | # node.js
7 | #
8 | node_modules/
9 | npm-debug.log
10 | yarn-error.log
11 | .history
12 | package-lock.json
13 |
14 |
15 | # Xcode
16 | #
17 | build/
18 | *.pbxuser
19 | !default.pbxuser
20 | *.mode1v3
21 | !default.mode1v3
22 | *.mode2v3
23 | !default.mode2v3
24 | *.perspectivev3
25 | !default.perspectivev3
26 | xcuserdata
27 | *.xccheckout
28 | *.moved-aside
29 | DerivedData
30 | *.hmap
31 | *.ipa
32 | *.xcuserstate
33 | project.xcworkspace
34 |
35 |
36 | # Android/IntelliJ
37 | #
38 | build/
39 | .idea
40 | .gradle
41 | local.properties
42 | *.iml
43 |
44 | # BUCK
45 | buck-out/
46 | \.buckd/
47 | *.keystore
48 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | README.md
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Maher Zaidoune
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # react-native-url-preview 🐜
3 |
4 | [](https://www.npmjs.com/package/react-native-url-preview)
5 |
6 |
7 | Parses text and wraps URLs , transform the url to a beautiful link preview
8 |
9 | ## Getting started 🐜
10 |
11 | `$ npm install react-native-url-preview --save`
12 |
13 | ## Usage 🐜
14 | ```javascript
15 | import RNUrlPreview from 'react-native-url-preview';
16 |
17 |
18 | ```
19 |
20 | ## Examples🐜
21 |
22 | Please refer to the [react-native-url-preview example](https://github.com/maherzaidoune/RNUrlPreviewExample) provided to see how `react-native-url-preview` can be used .
23 |
24 | ## Demo🐜
25 |
26 |
27 |
28 |
29 |
30 |
31 | ## Customization 🐜
32 |
33 | | Parameter | Required? | Default | Type | Description |
34 | | :----------------------- | :-------: | :------------------------- | :-------- | :----------------------------------------------------- |
35 | | text | YES | Null | `string` | The text that is parsed and where the URL is retrieved |
36 | | title | NO | True | `Boolean` | determine whether the URL title is displyed or not |
37 | | description | NO | True | `Boolean` | determine whether the URL description is displyed or not |
38 | | titleStyle | NO | defaultStyle | `style` | self explanatory i believe |
39 | | containerStyle | NO | defaultStyle | `style` | you can pass a custom container style |
40 | | imageStyle | NO | defaultStyle | `style` | you can pass a custom image style |
41 | | faviconStyle | NO | defaultStyle | `style` | you can pass a custom favicon style |
42 | | textContainerStyle | NO | defaultStyle | `style` | you can pass a custom style for the text container |
43 | | descriptionStyle | NO | defaultStyle | `style` | self explanatory i believe |
44 | | titleNumberOfLines | NO | 2 | `number` | self explanatory i believe |
45 | | descriptionNumberOfLines | NO | Ipad?4:3 | `number` | self explanatory i believe |
46 | | imageProps | NO | `{ resizeMode: "contain"}` | `object` | you can pass a custom props to image |
47 | | requestOptions | NO | `{}` | `object` | pass additional options to url preview request
48 | | onLoad | NO | `() => {}` | `function`| callback called when url preview data is loaded |
49 | | onError | NO | `() => {}` | `function`| callback called if url preview fails to load |
50 | ## Credits 🐜
51 |
52 | - Thanks to [marouan frih](https://github.com/Madm0x) for the REGEX
53 | - extract information from a URL with [link-preview-js](https://github.com/ospfranco/link-preview-js)
54 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {getLinkPreview} from 'link-preview-js';
3 | import PropTypes from 'prop-types';
4 | import {Image, Linking, Platform, Text, TouchableOpacity, View, ViewPropTypes} from 'react-native';
5 |
6 | const REGEX = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/g;
7 |
8 | export default class RNUrlPreview extends React.PureComponent {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | isUri: false,
13 | linkTitle: undefined,
14 | linkDesc: undefined,
15 | linkFavicon: undefined,
16 | linkImg: undefined,
17 | };
18 | this.getPreview(props.text, props.requestOptions);
19 | }
20 |
21 | getPreview = (text, options) => {
22 | const {onError, onLoad} = this.props;
23 | getLinkPreview(text, options)
24 | .then(data => {
25 | onLoad(data);
26 | this.setState({
27 | isUri: true,
28 | linkTitle: data.title ? data.title : undefined,
29 | linkDesc: data.description ? data.description : undefined,
30 | linkImg:
31 | data.images && data.images.length > 0
32 | ? data.images.find(function(element) {
33 | return element.includes('.png') || element.includes('.jpg') || element.includes('.jpeg');
34 | })
35 | : undefined,
36 | linkFavicon: data.favicons && data.favicons.length > 0 ? data.favicons[data.favicons.length - 1] : undefined,
37 | });
38 | })
39 | .catch(error => {
40 | onError(error);
41 | this.setState({isUri: false});
42 | });
43 | };
44 |
45 | componentDidUpdate(nextProps) {
46 | if (nextProps.text !== this.props.text) {
47 | this.getPreview(nextProps.text);
48 | } else if (nextProps.text == null) {
49 | this.setState({isUri: false});
50 | }
51 | }
52 |
53 | _onLinkPressed = () => {
54 | Linking.openURL(this.props.text.match(REGEX)[0]);
55 | };
56 |
57 | renderImage = (imageLink, faviconLink, imageStyle, faviconStyle, imageProps) => {
58 | return imageLink ? (
59 |
60 | ) : faviconLink ? (
61 |
62 | ) : null;
63 | };
64 | renderText = (showTitle, showDescription, title, description, textContainerStyle, titleStyle, descriptionStyle, titleNumberOfLines, descriptionNumberOfLines) => {
65 | return (
66 |
67 | {showTitle && (
68 |
69 | {title}
70 |
71 | )}
72 | {showDescription && (
73 |
74 | {description}
75 |
76 | )}
77 |
78 | );
79 | };
80 | renderLinkPreview = (
81 | containerStyle,
82 | imageLink,
83 | faviconLink,
84 | imageStyle,
85 | faviconStyle,
86 | showTitle,
87 | showDescription,
88 | title,
89 | description,
90 | textContainerStyle,
91 | titleStyle,
92 | descriptionStyle,
93 | titleNumberOfLines,
94 | descriptionNumberOfLines,
95 | imageProps,
96 | ) => {
97 | return (
98 | this._onLinkPressed()}>
99 | {this.renderImage(imageLink, faviconLink, imageStyle, faviconStyle, imageProps)}
100 | {this.renderText(showTitle, showDescription, title, description, textContainerStyle, titleStyle, descriptionStyle, titleNumberOfLines, descriptionNumberOfLines)}
101 |
102 | );
103 | };
104 |
105 | render() {
106 | const {
107 | text,
108 | containerStyle,
109 | imageStyle,
110 | faviconStyle,
111 | textContainerStyle,
112 | title,
113 | description,
114 | titleStyle,
115 | titleNumberOfLines,
116 | descriptionStyle,
117 | descriptionNumberOfLines,
118 | imageProps,
119 | } = this.props;
120 | return this.state.isUri
121 | ? this.renderLinkPreview(
122 | containerStyle,
123 | this.state.linkImg,
124 | this.state.linkFavicon,
125 | imageStyle,
126 | faviconStyle,
127 | title,
128 | description,
129 | this.state.linkTitle,
130 | this.state.linkDesc,
131 | textContainerStyle,
132 | titleStyle,
133 | descriptionStyle,
134 | titleNumberOfLines,
135 | descriptionNumberOfLines,
136 | imageProps,
137 | )
138 | : null;
139 | }
140 | }
141 |
142 | const styles = {
143 | containerStyle: {
144 | flexDirection: 'row',
145 | },
146 | };
147 |
148 | RNUrlPreview.defaultProps = {
149 | onLoad: () => {},
150 | onError: () => {},
151 | text: null,
152 | requestOptions: {},
153 | containerStyle: {
154 | backgroundColor: 'rgba(239, 239, 244,0.62)',
155 | alignItems: 'center',
156 | },
157 | imageStyle: {
158 | width: Platform.isPad ? 160 : 110,
159 | height: Platform.isPad ? 160 : 110,
160 | paddingRight: 10,
161 | paddingLeft: 10,
162 | },
163 | faviconStyle: {
164 | width: 40,
165 | height: 40,
166 | paddingRight: 10,
167 | paddingLeft: 10,
168 | },
169 | textContainerStyle: {
170 | flex: 1,
171 | justifyContent: 'flex-start',
172 | alignItems: 'flex-start',
173 | padding: 10,
174 | },
175 | title: true,
176 | description: true,
177 | titleStyle: {
178 | fontSize: 17,
179 | color: '#000',
180 | marginRight: 10,
181 | marginBottom: 5,
182 | alignSelf: 'flex-start',
183 | },
184 | titleNumberOfLines: 2,
185 | descriptionStyle: {
186 | fontSize: 14,
187 | color: '#81848A',
188 | marginRight: 10,
189 | alignSelf: 'flex-start',
190 | },
191 | descriptionNumberOfLines: Platform.isPad ? 4 : 3,
192 | imageProps: {resizeMode: 'contain'},
193 | };
194 |
195 | RNUrlPreview.propTypes = {
196 | onLoad: PropTypes.func,
197 | onError: PropTypes.func,
198 | text: PropTypes.string,
199 | containerStyle: ViewPropTypes ? ViewPropTypes.style : PropTypes.object,
200 | imageStyle: ViewPropTypes ? ViewPropTypes.style : PropTypes.object,
201 | faviconStyle: ViewPropTypes ? ViewPropTypes.style : PropTypes.object,
202 | textContainerStyle: ViewPropTypes ? ViewPropTypes.style : PropTypes.object,
203 | title: PropTypes.bool,
204 | description: PropTypes.bool,
205 | titleStyle: Text.propTypes ? Text.propTypes.style : PropTypes.object,
206 | titleNumberOfLines: Text.propTypes ? Text.propTypes.numberOfLines : PropTypes.number,
207 | descriptionStyle: Text.propTypes ? Text.propTypes.style : PropTypes.object,
208 | descriptionNumberOfLines: Text.propTypes ? Text.propTypes.numberOfLines : PropTypes.number,
209 | requestOptions: PropTypes.shape({
210 | headers: PropTypes.objectOf(PropTypes.string),
211 | imagesPropertyType: PropTypes.string,
212 | proxyUrl: PropTypes.string
213 | })
214 | };
215 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-url-preview",
3 | "version": "1.1.9",
4 | "description": "react native url previewer",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [
10 | "react-native",
11 | "react-component",
12 | "ios",
13 | "android",
14 | "url preview",
15 | "youtube video preview",
16 | "link preview"
17 | ],
18 | "author": "Zaidoune Maher",
19 | "license": "MIT",
20 | "peerDependencies": {
21 | "prop-types": "*",
22 | "react": "*",
23 | "react-native": "*",
24 | "react-native-windows": "0.41.0-rc.1"
25 | },
26 | "dependencies": {
27 | "link-preview-js": "2.0.4"
28 | },
29 | "devDependencies": {},
30 | "repository": {
31 | "type": "git",
32 | "url": "git+https://github.com/maherzaidoune/react-native-url-preview.git"
33 | },
34 | "bugs": {
35 | "url": "https://github.com/maherzaidoune/react-native-url-preview/issues"
36 | },
37 | "homepage": "https://github.com/maherzaidoune/react-native-url-preview#readme"
38 | }
39 |
--------------------------------------------------------------------------------