├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── index.js
├── package.json
├── view.gif
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | view.gif
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017
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 | # react-native-tooltip-view
2 | A dead simple tooltip view that you can populate yourself
3 |
4 | ## Installation
5 | ```
6 | $ yarn add react-native-tooltip-view
7 | ```
8 | Be aware that this package depends on recompose and styled-components are peer dependencies.
9 | So if you aren't using them install with:
10 | ```
11 | $ yarn add recompose styled-components
12 | ```
13 | And you should totally give a try with those awesome packages!
14 |
15 | ## Demo
16 | 
17 |
18 | ## Usage
19 |
20 | ```js
21 | import TooltipView from 'react-native-tooltip-view'
22 | ...
23 |
24 | function Foo() {
25 | return (
26 | }
29 | // you can pass an optional width for the tooltip
30 | width={200}
31 | // and also an optional background
32 | backgroundColor="#f9f9f9"
33 | // `triangleStyle`={{}} to style the little triangle
34 | // and any valid View props
35 | >
36 | {setMenuVisibility => (
37 | // anything you want in here
38 | )}
39 |
40 | )
41 | }
42 | ```
43 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Platform, Dimensions, View, Modal, InteractionManager } from 'react-native'
3 | import PropTypes from 'prop-types'
4 | import styled from 'styled-components/native'
5 | import { compose, pure, withStateHandlers, withHandlers } from 'recompose'
6 |
7 | const WINDOW_DIMENSIONS = Dimensions.get('window')
8 |
9 | const TooltipWrapper = styled.View.attrs({
10 | style: {
11 | shadowOffset: { height: 1.8 },
12 | },
13 | })`
14 | width: ${props => props.width};
15 | position: absolute;
16 | shadowRadius: 1.62;
17 | shadowOpacity: 0.1845;
18 | bottom: ${props => props.bottom};
19 | left: ${props => props.left};
20 | background-color: ${props => props.backgroundColor || '#fff'};
21 | `
22 |
23 | const Triangle = styled.View`
24 | position: absolute;
25 | bottom: ${props => props.bottom - props.size};
26 | left: ${props => props.left};
27 | width: ${props => props.size};
28 | height: ${props => props.size};
29 | background-color: transparent;
30 | border-style: solid;
31 | border-top-width: ${props => props.size};
32 | border-right-width: ${props => props.size};
33 | border-bottom-width: 0;
34 | border-left-width: ${props => props.size};
35 | border-top-color: ${props => props.backgroundColor || '#fff'};
36 | border-right-color: transparent;
37 | border-bottom-color: transparent;
38 | border-left-color: transparent;
39 | `
40 |
41 | const OverlayTouchable = styled.TouchableWithoutFeedback`
42 | flex: 1;
43 | `
44 |
45 | const OverlayContentWrapper = styled.View`flex: 1;`
46 |
47 | function TooltipOptionsMenu({
48 | isMenuActive,
49 | setMenuVisibility,
50 | showMenu,
51 | hideMenu,
52 | children,
53 | trigger,
54 | tooltipCoords,
55 | initPositioning,
56 | triangleProps,
57 | setWrapperRef,
58 | ...props
59 | }) {
60 | return (
61 | setWrapperRef(ref)}>
62 |
63 |
64 |
65 |
66 |
67 | {children(setMenuVisibility)}
68 |
69 |
70 |
71 |
72 | {trigger(showMenu)}
73 |
74 | )
75 | }
76 |
77 | TooltipOptionsMenu.propTypes = {
78 | isMenuActive: PropTypes.bool.isRequired,
79 | tooltipCoords: PropTypes.object.isRequired,
80 | initPositioning: PropTypes.func.isRequired,
81 | setMenuVisibility: PropTypes.func.isRequired,
82 | trigger: PropTypes.func.isRequired,
83 | triangleProps: PropTypes.object,
84 | children: PropTypes.func.isRequired,
85 | }
86 |
87 | TooltipOptionsMenu.defaultProps = {
88 | triangleProps: {},
89 | }
90 |
91 | export default compose(
92 | withStateHandlers({
93 | isMenuActive: false,
94 | tooltipCoords: {},
95 | wrapperRef: {},
96 | }, {
97 | setMenuVisibility: () => value => ({ isMenuActive: value }),
98 | hideMenu: () => () => ({ isMenuActive: false }),
99 | showMenu: () => () => ({ isMenuActive: true }),
100 | setTooltipCoords: () => tooltipCoords => ({ tooltipCoords }),
101 | setWrapperRef: () => wrapperRef => ({ wrapperRef }),
102 | }),
103 | withHandlers({
104 | initPositioning: props => layoutEvent => {
105 | const { layout } = layoutEvent.nativeEvent
106 |
107 | // If the TooltipView is used within a tabs container or a navigator
108 | // with transitions we would get different values for pageX and pageY all the time.
109 | // So here we ensure we are going to get our sweet values only after those transitions have ended.
110 | InteractionManager.runAfterInteractions(() => {
111 | props.wrapperRef.measure((x, y, width, height, pageX, pageY) => {
112 | props.setTooltipCoords({
113 | bottom: WINDOW_DIMENSIONS.height - (layout.height + pageY) + Platform.select({android: 0, ios: 30}),
114 | left: pageX + layout.width - 10,
115 | width: WINDOW_DIMENSIONS.width - layout.x - pageX - 10,
116 | })
117 | })
118 | })
119 | },
120 | }),
121 | pure,
122 | )(TooltipOptionsMenu)
123 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-tooltip-view",
3 | "version": "2.1.0",
4 | "description": "A dead simple tooltip view that you pass your own children",
5 | "main": "index.js",
6 | "repository": "https://github.com/Astrocoders/react-native-tooltip-view.git",
7 | "author": "Gabriel R. Abreu ",
8 | "license": "MIT",
9 | "peerDependencies": {
10 | "prop-types": "^15.5.10",
11 | "react": "^15.6.1",
12 | "react-native": "^0.45.1",
13 | "recompose": "^0.23.5",
14 | "styled-components": "^2.1.1"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/view.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Astrocoders/react-native-tooltip-view/5f58d7504e9be8a39681e5dfec6166dc5a24df60/view.gif
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.5"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
8 |
9 | change-emitter@^0.1.2:
10 | version "0.1.6"
11 | resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515"
12 |
13 | core-js@^1.0.0:
14 | version "1.2.7"
15 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
16 |
17 | encoding@^0.1.11:
18 | version "0.1.12"
19 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
20 | dependencies:
21 | iconv-lite "~0.4.13"
22 |
23 | fbjs@^0.8.1:
24 | version "0.8.12"
25 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
26 | dependencies:
27 | core-js "^1.0.0"
28 | isomorphic-fetch "^2.1.1"
29 | loose-envify "^1.0.0"
30 | object-assign "^4.1.0"
31 | promise "^7.1.1"
32 | setimmediate "^1.0.5"
33 | ua-parser-js "^0.7.9"
34 |
35 | hoist-non-react-statics@^1.0.0:
36 | version "1.2.0"
37 | resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
38 |
39 | iconv-lite@~0.4.13:
40 | version "0.4.18"
41 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
42 |
43 | is-stream@^1.0.1:
44 | version "1.1.0"
45 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
46 |
47 | isomorphic-fetch@^2.1.1:
48 | version "2.2.1"
49 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
50 | dependencies:
51 | node-fetch "^1.0.1"
52 | whatwg-fetch ">=0.10.0"
53 |
54 | js-tokens@^3.0.0:
55 | version "3.0.2"
56 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
57 |
58 | loose-envify@^1.0.0:
59 | version "1.3.1"
60 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
61 | dependencies:
62 | js-tokens "^3.0.0"
63 |
64 | node-fetch@^1.0.1:
65 | version "1.7.1"
66 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5"
67 | dependencies:
68 | encoding "^0.1.11"
69 | is-stream "^1.0.1"
70 |
71 | object-assign@^4.1.0:
72 | version "4.1.1"
73 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
74 |
75 | promise@^7.1.1:
76 | version "7.3.1"
77 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
78 | dependencies:
79 | asap "~2.0.3"
80 |
81 | recompose@^0.23.5:
82 | version "0.23.5"
83 | resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.23.5.tgz#72ac8261246bec378235d187467d02a721e8b1de"
84 | dependencies:
85 | change-emitter "^0.1.2"
86 | fbjs "^0.8.1"
87 | hoist-non-react-statics "^1.0.0"
88 | symbol-observable "^1.0.4"
89 |
90 | setimmediate@^1.0.5:
91 | version "1.0.5"
92 | resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
93 |
94 | symbol-observable@^1.0.4:
95 | version "1.0.4"
96 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
97 |
98 | ua-parser-js@^0.7.9:
99 | version "0.7.13"
100 | resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.13.tgz#cd9dd2f86493b3f44dbeeef3780fda74c5ee14be"
101 |
102 | whatwg-fetch@>=0.10.0:
103 | version "2.0.3"
104 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
105 |
--------------------------------------------------------------------------------