├── .editorconfig ├── .eslintrc ├── .gitignore ├── .travis.yml ├── README.md ├── package.json ├── rollup.config.js ├── src └── index.js └── test └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [{package.json,.*rc,*.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "eslint:recommended", 4 | "env": { 5 | "browser": true 6 | }, 7 | "plugins": [ 8 | "react" 9 | ], 10 | "settings": { 11 | "react": { 12 | "pragma": "h" 13 | } 14 | }, 15 | "parserOptions": { 16 | "ecmaVersion": 6, 17 | "sourceType": "module", 18 | "ecmaFeatures": { 19 | "modules": true, 20 | "jsx": true 21 | } 22 | }, 23 | "rules": { 24 | "react/jsx-uses-react": 2, 25 | "react/jsx-uses-vars": 2, 26 | "no-unused-vars": [1, { "varsIgnorePattern": "^h$" }], 27 | "no-cond-assign": 1, 28 | "semi": 2, 29 | "camelcase": 0, 30 | "comma-style": 2, 31 | "comma-dangle": [2, "never"], 32 | "indent": [2, "tab", {"SwitchCase": 1}], 33 | "no-mixed-spaces-and-tabs": [2, "smart-tabs"], 34 | "no-trailing-spaces": [2, { "skipBlankLines": true }], 35 | "max-nested-callbacks": [2, 3], 36 | "no-eval": 2, 37 | "no-implied-eval": 2, 38 | "no-new-func": 2, 39 | "guard-for-in": 2, 40 | "eqeqeq": 2, 41 | "no-else-return": 2, 42 | "no-redeclare": 2, 43 | "no-dupe-keys": 2, 44 | "radix": 2, 45 | "strict": [2, "never"], 46 | "no-shadow": 0, 47 | "callback-return": [1, ["callback", "cb", "next", "done"]], 48 | "no-delete-var": 2, 49 | "no-undef-init": 2, 50 | "no-shadow-restricted-names": 2, 51 | "handle-callback-err": 0, 52 | "no-lonely-if": 2, 53 | "keyword-spacing": 2, 54 | "constructor-super": 2, 55 | "no-this-before-super": 2, 56 | "no-dupe-class-members": 2, 57 | "no-const-assign": 2, 58 | "prefer-spread": 2, 59 | "no-useless-concat": 2, 60 | "no-var": 2, 61 | "object-shorthand": 2, 62 | "prefer-arrow-callback": 2 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /node_modules 3 | /npm-debug.log 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # preact-tap-event-plugin: `onTouchTap` _for [Preact]_ 2 | 3 | [![NPM](https://img.shields.io/npm/v/preact-tap-event-plugin.svg)](https://www.npmjs.com/package/preact-tap-event-plugin) 4 | [![Travis](https://travis-ci.org/developit/preact-tap-event-plugin.svg?branch=master)](https://travis-ci.org/developit/preact-tap-event-plugin) 5 | 6 | `onTouchTap` is a [FastClick]-style instant "click" event, triggered by `touchstart` and `touchend` occurring within a 10-pixel radius. 7 | 8 | > This module intentionally has the same interface as [react-tap-event-plugin](https://github.com/zilverline/react-tap-event-plugin) so that it can be used as a drop-in alias when working with [preact-compat](https://github.com/developit/preact-compat). 9 | 10 | #### [JSFiddle Demo](https://jsfiddle.net/developit/rq877gp3/) 11 | 12 | 13 | --- 14 | 15 | 16 | ## Usage Example 17 | 18 | `npm i -S preact-tap-event-plugin` 19 | 20 | 21 | ```js 22 | import injectTapEventPlugin from 'preact-tap-event-plugin'; 23 | 24 | injectTapEventPlugin(); 25 | ``` 26 | 27 | 28 | --- 29 | 30 | 31 | ## License 32 | 33 | [MIT] 34 | 35 | 36 | [Preact]: https://github.com/developit/preact 37 | [FastClick]: https://github.com/ftlabs/fastclick 38 | [MIT]: http://choosealicense.com/licenses/mit/ 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preact-tap-event-plugin", 3 | "amdName": "injectTapEventPlugin", 4 | "version": "0.1.2", 5 | "description": "Use onTouchTap in Preact", 6 | "main": "dist/preact-tap-event-plugin.js", 7 | "minified:main": "dist/preact-tap-event-plugin.min.js", 8 | "jsnext:main": "src/index.js", 9 | "scripts": { 10 | "build": "npm-run-all transpile optimize minify", 11 | "transpile": "rollup -c rollup.config.js -m ${npm_package_main}.map -f umd -n $npm_package_amdName $npm_package_jsnext_main -o $npm_package_main", 12 | "optimize": "uglifyjs $npm_package_main -bc dead_code --pure-funcs _possibleConstructorReturn _classCallCheck -o $npm_package_main -p relative --in-source-map ${npm_package_main}.map --source-map ${npm_package_main}.map", 13 | "minify": "uglifyjs $npm_package_main -mc collapse_vars,evaluate,screw_ie8,unsafe,loops=false,keep_fargs=false,pure_getters,unused,dead_code --pure-funcs _possibleConstructorReturn _classCallCheck -o $npm_package_minified_main -p relative --in-source-map ${npm_package_main}.map --source-map ${npm_package_minified_main}.map", 14 | "test": "eslint {src,test} && mocha --compilers js:babel-register test/**/*.js", 15 | "prepublish": "npm run build", 16 | "release": "npm run build && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish" 17 | }, 18 | "babel": { 19 | "presets": [ 20 | "es2015", 21 | "stage-0" 22 | ], 23 | "plugins": [ 24 | "transform-class-properties", 25 | [ 26 | "transform-react-jsx", 27 | { 28 | "pragma": "h" 29 | } 30 | ] 31 | ] 32 | }, 33 | "keywords": [ 34 | "preact", 35 | "tap", 36 | "event", 37 | "plugin" 38 | ], 39 | "files": [ 40 | "src", 41 | "dist" 42 | ], 43 | "author": "Jason Miller ", 44 | "license": "MIT", 45 | "repository": { 46 | "type": "git", 47 | "url": "git+https://github.com/developit/preact-tap-event-plugin.git" 48 | }, 49 | "bugs": { 50 | "url": "https://github.com/developit/preact-tap-event-plugin/issues" 51 | }, 52 | "homepage": "https://github.com/developit/preact-tap-event-plugin", 53 | "devDependencies": { 54 | "babel": "^6.5.2", 55 | "babel-eslint": "^7.1.0", 56 | "babel-plugin-transform-class-properties": "^6.18.0", 57 | "babel-plugin-transform-es2015-classes-simple": "^1.0.0", 58 | "babel-plugin-transform-react-jsx": "^6.8.0", 59 | "babel-preset-es2015": "^6.18.0", 60 | "babel-preset-stage-0": "^6.16.0", 61 | "babel-register": "^6.18.0", 62 | "chai": "^3.5.0", 63 | "eslint": "^3.10.2", 64 | "eslint-plugin-react": "^6.7.1", 65 | "mocha": "^3.1.2", 66 | "npm-run-all": "^3.1.1", 67 | "preact": "^7.1.0", 68 | "rollup": "^0.36.3", 69 | "rollup-plugin-babel": "^2.6.1", 70 | "rollup-plugin-es3": "^1.0.3", 71 | "uglify-js": "^2.7.4" 72 | }, 73 | "peerDependencies": { 74 | "preact": "*" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import es3 from 'rollup-plugin-es3'; 3 | 4 | export default { 5 | useStrict: false, 6 | plugins: [ 7 | babel({ 8 | babelrc: false, 9 | sourceMap: true, 10 | exclude: 'node_modules/**', 11 | presets: [ 12 | ['es2015', { modules:false, loose:true }], 13 | 'stage-0' 14 | ], 15 | plugins: [ 16 | 'transform-class-properties', 17 | ['transform-react-jsx', { pragma:'h' }] 18 | ] 19 | }), 20 | es3() 21 | ] 22 | }; 23 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { options } from 'preact'; 2 | 3 | 4 | const OPTS = { 5 | // # of pixels after which to discount as drag op 6 | threshold: 10 7 | }; 8 | 9 | 10 | let injected, hasTouch; 11 | 12 | 13 | // in case someone calls inject(): 14 | export default opts => { 15 | for (let i in opts) if (opts.hasOwnProperty(i)) OPTS[i] = opts[i]; 16 | 17 | if (injected) return; 18 | injected = true; 19 | 20 | let oldHook = options.vnode; 21 | options.vnode = vnode => { 22 | let attrs = 'props' in vnode ? vnode.props : vnode.attributes; 23 | if (attrs) { 24 | for (let i in attrs) { 25 | if (attrs.hasOwnProperty(i) && i.toLowerCase()==='ontouchtap') { 26 | proxy(attrs); 27 | break; 28 | } 29 | } 30 | } 31 | if (oldHook) oldHook(vnode); 32 | }; 33 | }; 34 | 35 | 36 | function proxy(attrs) { 37 | let map = {}; 38 | for (let i in attrs) if (attrs.hasOwnProperty(i)) { 39 | map[i.toLowerCase()] = i; 40 | } 41 | 42 | let start = attrs[map.ontouchstart], 43 | tap = attrs[map.ontouchtap], 44 | click = attrs[map.onclick]; 45 | 46 | delete attrs[map.ontouchtap]; 47 | 48 | attrs[map.onclick || 'onClick'] = e => { 49 | if (click) click(e); 50 | if (!hasTouch) return tap(e); 51 | }; 52 | 53 | attrs[map.ontouchstart || 'onTouchStart'] = e => { 54 | let down = coords(e); 55 | hasTouch = true; 56 | 57 | addEventListener('touchend', function onEnd(e) { 58 | removeEventListener('touchend', onEnd); 59 | let up = coords(e), 60 | dist = Math.sqrt( Math.pow(up.x-down.x,2) + Math.pow(up.y-down.y,2) ); 61 | if (dist { 8 | it('should export a class', () => { 9 | expect(injectTapEventPlugin).to.be.a('function'); 10 | }); 11 | 12 | xit('should have proper tests', () => {}); 13 | }); 14 | --------------------------------------------------------------------------------