Skip to content

Commit 0eb1e4a

Browse files
authored
Bugfix/several bugs (#7)
* change main file package.json * several improvements * suggestions and fixes * other fixes * types safety * fixes on handlers
1 parent 1e0d48a commit 0eb1e4a

10 files changed

+2370
-97
lines changed

.eslintrc.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,15 @@ module.exports = {
88
'simple-import-sort/imports': 'error',
99
'sort-imports': 'off',
1010
},
11+
settings: {
12+
'import/extensions': ['.js', '.ts', '.tsx'],
13+
'import/parsers': {
14+
'@typescript-eslint/parser': ['.ts', '.tsx'],
15+
},
16+
'import/resolver': {
17+
node: {
18+
extensions: ['.js', '.ts', '.tsx'],
19+
},
20+
},
21+
},
1122
}

babel.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./lib/module/babel/index.js')

package.json

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,37 @@
11
{
22
"name": "react-native-vimeo-iframe",
3-
"version": "1.0.1",
4-
"description": "",
3+
"version": "1.0.2",
4+
"description": "React Native Vimeo Iframe is a library to render Vimeo videos in a React Native app. This component allows you to embed a Vimeo video in your app and have full access to the Vimeo player JS API (more information https://developer.vimeo.com/player/js-api).",
55
"homepage": "https://github.com/MetaLabs-inc/react-native-vimeo-iframe#readme",
6-
"main": "src/index.tsx",
7-
"types": "lib/index.d.ts",
6+
"main": "lib/commonjs/index.js",
7+
"types": "lib/typescript/index.d.ts",
8+
"module": "lib/module/index.js",
9+
"react-native": "src/index.tsx",
10+
"source": "src/index.tsx",
811
"author": "Marco Fiorito <[email protected]>",
912
"license": "MIT",
1013
"files": [
11-
"lib"
14+
"src",
15+
"lib",
16+
"babel.js"
17+
],
18+
"repository": {
19+
"type": "git",
20+
"url": "https://github.com/MetaLabs-inc/react-native-vimeo-iframe"
21+
},
22+
"keywords": [
23+
"android",
24+
"ios",
25+
"react native",
26+
"component library",
27+
"vimeo",
28+
"videos"
1229
],
1330
"scripts": {
31+
"typescript": "tsc --noEmit",
32+
"prepare": "bob build && node ./scripts/generate-mappings.js",
1433
"compile": "rm -rf lib && tsc -p .",
1534
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
16-
"prepare": "yarn compile",
1735
"test": "jest"
1836
},
1937
"devDependencies": {
@@ -28,14 +46,18 @@
2846
"eslint-plugin-simple-import-sort": "^7.0.0",
2947
"jest": "^26.6.3",
3048
"metro-react-native-babel-preset": "^0.65.0",
49+
"babel-cli": "^6.26.0",
3150
"react": "^17.0.1",
3251
"react-native": "^0.63.4",
3352
"react-test-renderer": "^17.0.1",
34-
"typescript": "^4.1.3"
53+
"react-native-webview": "11.2.3",
54+
"typescript": "^4.1.3",
55+
"react-native-builder-bob": "^0.17.1"
3556
},
3657
"peerDependencies": {
37-
"react-native": "^0.63.4",
38-
"react-native-webview": "11.2.3"
58+
"react": "*",
59+
"react-native": "*",
60+
"react-native-webview": "*"
3961
},
4062
"jest": {
4163
"preset": "react-native",
@@ -47,5 +69,22 @@
4769
"json",
4870
"node"
4971
]
72+
},
73+
"react-native-builder-bob": {
74+
"source": "src",
75+
"output": "lib",
76+
"targets": [
77+
"commonjs",
78+
"module",
79+
[
80+
"typescript",
81+
{
82+
"project": "tsconfig.build.json"
83+
}
84+
]
85+
],
86+
"files": [
87+
"src/"
88+
]
5089
}
5190
}

scripts/generate-mappings.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* @flow */
2+
3+
const path = require('path')
4+
const fs = require('fs')
5+
const types = require('babel-types')
6+
const parser = require('@babel/parser')
7+
8+
const packageJson = require('../package.json')
9+
const root = path.resolve(__dirname, '..')
10+
const output = path.join(root, 'lib/mappings.json')
11+
const source = fs.readFileSync(path.resolve(root, 'src', 'index.tsx'), 'utf8')
12+
const ast = parser.parse(source, {
13+
sourceType: 'module',
14+
plugins: [
15+
'jsx',
16+
'typescript',
17+
'objectRestSpread',
18+
'classProperties',
19+
'asyncGenerators',
20+
],
21+
})
22+
23+
const index = packageJson.module
24+
const relative = (value /* : string */) =>
25+
path.relative(root, path.resolve(path.dirname(index), value))
26+
27+
const mappings = ast.program.body.reduce((acc, declaration, index, self) => {
28+
if (types.isExportNamedDeclaration(declaration)) {
29+
if (declaration.source) {
30+
declaration.specifiers.forEach((specifier) => {
31+
acc[specifier.exported.name] = {
32+
path: relative(declaration.source.value),
33+
name: specifier.local.name,
34+
}
35+
})
36+
} else {
37+
declaration.specifiers.forEach((specifier) => {
38+
const name = specifier.exported.name
39+
40+
self.forEach((it) => {
41+
if (
42+
types.isImportDeclaration(it) &&
43+
it.specifiers.some(
44+
(s) =>
45+
types.isImportNamespaceSpecifier(s) &&
46+
s.local.name === specifier.local.name
47+
)
48+
) {
49+
acc[name] = {
50+
path: relative(it.source.value),
51+
name: '*',
52+
}
53+
}
54+
})
55+
})
56+
}
57+
}
58+
59+
return acc
60+
}, {})
61+
62+
fs.existsSync(path.dirname(output)) || fs.mkdirSync(path.dirname(output))
63+
fs.writeFileSync(
64+
output,
65+
JSON.stringify({ name: packageJson.name, index, mappings }, null, 2)
66+
)

src/index.tsx

Lines changed: 107 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import React from 'react'
2-
import { TouchableWithoutFeedback } from 'react-native'
1+
import React, { useCallback, useEffect, useRef, useState } from 'react'
32
import { WebView } from 'react-native-webview'
43

54
import webplayer from './template'
6-
import { LayoutProps } from './types'
5+
import { LayoutProps, PlayerActions, PlayerEvents } from './types'
76

87
export const Vimeo: React.FC<LayoutProps> = ({
98
videoId,
@@ -18,70 +17,132 @@ export const Vimeo: React.FC<LayoutProps> = ({
1817
autoPlay,
1918
speed = false,
2019
style,
20+
onVolumeChange,
21+
onError,
22+
containerStyle,
23+
getVimeoPlayer,
2124
}) => {
22-
const [isReady, setReady] = React.useState<boolean>()
25+
const [isPlaying, setPlaying] = useState<boolean>(false)
26+
const ref = useRef<WebView>()
2327

24-
const [autoPlayValue, setAutoPlay] = React.useState<boolean>(autoPlay)
25-
const toggleAutoPlay = React.useCallback(() => setAutoPlay(!autoPlayValue), [
28+
const [autoPlayValue, setAutoPlay] = useState<boolean>(autoPlay)
29+
const toggleAutoPlay = useCallback(() => setAutoPlay(!autoPlayValue), [
2630
autoPlayValue,
2731
])
2832

2933
const handlers: any = {}
30-
const registerHandlers = () => {
31-
registerBridgeEventHandler('ready', onReady ?? onReadyDefault)
34+
35+
const player = useCallback(
36+
(action: PlayerActions) => {
37+
const handler = ref?.current?.injectJavaScript
38+
39+
if (handler) {
40+
switch (action.type) {
41+
case PlayerEvents.PLAY:
42+
if (isPlaying) return
43+
handler('play();')
44+
setPlaying(true)
45+
break
46+
case PlayerEvents.PAUSE:
47+
if (!isPlaying) return
48+
handler('await pause();')
49+
setPlaying(false)
50+
break
51+
case PlayerEvents.SET_TIME:
52+
handler(`setTime(${action.time});`)
53+
break
54+
case PlayerEvents.GET_DURATION:
55+
handler(`
56+
const videoDuration = getDuration();
57+
const callback = ${action.callback};
58+
callback(videoDuration);
59+
`)
60+
break
61+
default:
62+
break
63+
}
64+
}
65+
},
66+
[ref, isPlaying]
67+
)
68+
69+
const onReadyDefault = useCallback(() => {
70+
onReady && setTimeout(onReady)
71+
}, [onReady])
72+
73+
const registerHandlers = useCallback(() => {
74+
registerBridgeEventHandler('ready', onReadyDefault)
3275
registerBridgeEventHandler('play', onPlay)
3376
registerBridgeEventHandler('playProgress', onPlayProgress)
3477
registerBridgeEventHandler('pause', onPause)
3578
registerBridgeEventHandler('finish', onFinish)
36-
}
79+
registerBridgeEventHandler('volumeChange', onVolumeChange)
80+
registerBridgeEventHandler('error', onError)
81+
}, [
82+
onReadyDefault,
83+
onPlay,
84+
onPlayProgress,
85+
onError,
86+
onVolumeChange,
87+
onPause,
88+
onFinish,
89+
])
3790

3891
const registerBridgeEventHandler = (eventName: string, handler: any) => {
3992
handlers[eventName] = handler
4093
}
4194

42-
React.useEffect(() => {
95+
useEffect(() => {
4396
registerHandlers()
4497
}, [videoId, scalesPageToFit])
4598

46-
const onBridgeMessage = (event: any) => {
47-
const message = event.nativeEvent.data
48-
let payload
49-
try {
50-
payload = JSON.parse(message)
51-
if (payload?.name === 'finish') {
52-
toggleAutoPlay()
99+
const onBridgeMessage = useCallback(
100+
(event: any) => {
101+
const message = event.nativeEvent.data
102+
let payload
103+
try {
104+
payload = JSON.parse(message)
105+
if (payload?.name === 'finish') {
106+
toggleAutoPlay()
107+
}
108+
} catch (err) {
109+
return
53110
}
54-
} catch (err) {
55-
return
56-
}
57-
let handler = handlers[payload.name]
58-
if (handler) handler(payload.data)
59-
}
60111

61-
const onReadyDefault = () => {
62-
setReady(true)
63-
if (onReady) setTimeout(onReady)
64-
}
112+
let bridgeMessageHandler = handlers[payload?.name]
113+
if (bridgeMessageHandler) bridgeMessageHandler(payload?.data)
114+
},
115+
[toggleAutoPlay, handlers]
116+
)
117+
118+
useEffect(() => {
119+
getVimeoPlayer && getVimeoPlayer(player)
120+
}, [getVimeoPlayer, player])
65121

66122
return (
67-
<TouchableWithoutFeedback onPress={toggleAutoPlay}>
68-
<WebView
69-
source={{
70-
html: webplayer(videoId, loop, autoPlayValue, controls, speed),
71-
}}
72-
javaScriptEnabled={true}
73-
bounces={false}
74-
onMessage={onBridgeMessage}
75-
scalesPageToFit={scalesPageToFit}
76-
onError={(error) => console.error(error)}
77-
style={[
78-
{
79-
marginTop: -8,
80-
marginLeft: -10,
81-
},
82-
style,
83-
]}
84-
/>
85-
</TouchableWithoutFeedback>
123+
<WebView
124+
source={{
125+
html: webplayer(videoId, loop, autoPlayValue, controls, speed),
126+
}}
127+
javaScriptEnabled={true}
128+
ref={ref as any}
129+
onMessage={onBridgeMessage}
130+
bounces={false}
131+
scrollEnabled={false}
132+
scalesPageToFit={scalesPageToFit}
133+
onError={(error) => console.error(error)}
134+
style={[
135+
{
136+
marginTop: -8,
137+
marginLeft: -10,
138+
},
139+
style,
140+
]}
141+
containerStyle={containerStyle}
142+
setBuiltInZoomControls={false}
143+
setDisplayZoomControls={false}
144+
automaticallyAdjustContentInsets
145+
onNavigationStateChange={(a) => console.log(a?.url)}
146+
/>
86147
)
87148
}

src/template/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export default (
33
loop: boolean,
44
autoPlay: boolean,
55
controls: boolean,
6-
speed: boolean,
6+
speed: boolean
77
) => `
88
<html><head>
99
<title></title>
@@ -74,4 +74,4 @@ const sendEvent = (evt, data) => {
7474
webViewBridge();
7575
</script>
7676
</body></html>
77-
`;
77+
`

0 commit comments

Comments
 (0)