Skip to content

Commit fb56441

Browse files
committed
Merge branch 'add-long-press'
2 parents 70a3d18 + 118c777 commit fb56441

14 files changed

Lines changed: 4229 additions & 267 deletions

.eslintrc.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module.exports = {
2+
root: true,
3+
parser: 'babel-eslint',
4+
env: {
5+
browser: true,
6+
node: true,
7+
},
8+
extends: ['airbnb', 'prettier', 'prettier/react'],
9+
plugins: ['react', 'prettier'],
10+
rules: {
11+
'no-unused-expressions': [
12+
'error',
13+
{ allowShortCircuit: true, allowTernary: true },
14+
],
15+
'no-plusplus': 'off',
16+
'no-param-reassign': ['error', { props: false }],
17+
'import/no-unresolved': ['error', { ignore: ['^react$'] }],
18+
'import/extensions': ['error', 'never'],
19+
'react/jsx-filename-extension': 'off',
20+
'prettier/prettier': ['warn', { trailingComma: 'all', singleQuote: true }],
21+
},
22+
};

.eslintrc.json

Lines changed: 0 additions & 23 deletions
This file was deleted.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ import { Link } from 'react-router-dom';
147147

148148
#### Installing `react-interactive`
149149
```shell
150+
$ yarn add react-interactive
151+
# OR
150152
$ npm install --save react-interactive
151153
```
152154
```javascript
@@ -184,6 +186,8 @@ For the definition of when each state is entered, see the [state machine definit
184186
| `setStateCallback` | function | `function({ prevState, nextState }) {...}` | Function passed in as a callback when RI calls `setState`. Receives the same object as `onStateChange` as its sole argument, except without the `event` key (`setState` is asynchronous and React events don't persist asynchronously). Use this hook if you need to wait until the DOM is updated before executing the callback. |
185187
| `onClick` | function | `function(event, clickType) {...}` <br><br> Where `clickType` is one of: <br> `'mouseClick'` <br> `'tapClick'` <br> `'keyClick'` | Function called for mouse clicks, touch taps with 1 touch point/finger (called without delay), enter keydown events (if the element has focus), and synthetic click events. The `event` argument will always be a `click` event (`node.click()` is called to generate a click event if needed). The `clickType` argument will always be one of `mouseClick`, `tapClick`, or `keyClick`. It will be `mouseClick` for mouse clicks and for synthetic click events on mouse only and hybrid devices. It will be `tapClick` for touch taps with 1 touch point and for synthetic click events on touch only devices. It will be `keyClick` if the click event was generated from a enter keydown event (or, for some elements, a space keyup event). Note that RI will call `node.click()` for enter keydown events only if there is an `onClick` prop. |
186188
| `onTapTwo` | function | `function(event) {...}` | Function called for taps with 2 touch points, e.g. a 2 finger tap. Event passed in is the `touchend` event from last touch point to leave the surface. |
189+
| `tapTimeCutoff` | whole number | `500` | Number of ms to allow for a tap. This is the cutoff time that separates a tap from a long press. This prop is not required and the default is `500`. |
190+
| `onLongPress` | function | `function(event) {...}` | Function called on long press if touch is present after the `tapTimeCutoff` and if the touch has not moved more than is allowed for a `tap`. Event passed in is the touch start event that started the long press. |
187191
| `touchActiveTapOnly` | boolean | `touchActiveTapOnly` | Add this prop to only remain in the `touchActive` state while a tap is possible. If the touch is moved more than the tolerance for a tap, or held on the screen longer than the time allowed for a tap, then the `touchActive` state is exited. This is useful when the intention of the `touchActive` state is to indicate to the user that they are tapping something. Note that without this prop React Interactive will remain in the `touchActive` state as long as the touch point is on the screen.
188192
| `extraTouchNoTap` | boolean | `extraTouchNoTap` | Add this prop to cancel taps while touching someplace else on the screen. By default RI will ignore extra touches on the screen and allow taps on the RI element regardless of other touches. |
189193
| `nonContainedChild` | boolean | `nonContainedChild` | Add this prop if the DOM node's children are not contained inside of it on the page. For example, a child that is absolutely positioned outside of its parent. React Interactive does some quality control checks using `node.getBoundingClientRect()`, and by default the children are assumed to be within the parent's rectangle, but if this is not the case, then add this prop and the children will be checked. |

package.json

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
"description": "React Interactive",
55
"main": "lib/index.js",
66
"scripts": {
7-
"build": "npm run build-lib && npm run build-dist",
7+
"build": "yarn build-lib && yarn build-dist",
88
"build-lib": "rm -rf lib && babel src -d lib",
99
"build-dist": "rm -rf dist && webpack src/index.js dist/ReactInteractive.js && webpack -p src/index.js dist/ReactInteractive.min.js",
10-
"prepublish": "npm run build",
11-
"dev": "npm link && babel src -d lib --watch"
10+
"prepublish": "yarn build",
11+
"dev": "yarn link && babel src -d lib --watch"
1212
},
1313
"files": [
1414
"src",
@@ -37,22 +37,25 @@
3737
"react": "^15.5.0"
3838
},
3939
"devDependencies": {
40-
"babel-cli": "^6.24.1",
40+
"babel-cli": "^6.26.0",
4141
"babel-eslint": "^7.2.3",
4242
"babel-loader": "^7.0.0",
4343
"babel-plugin-add-module-exports": "^0.2.1",
4444
"babel-preset-env": "^1.4.0",
4545
"babel-preset-react": "^6.24.1",
4646
"babel-preset-stage-1": "^6.24.1",
47-
"eslint": "^3.19.0",
48-
"eslint-config-airbnb": "^14.1.0",
47+
"eslint": "^4.4.1",
48+
"eslint-config-airbnb": "^15.1.0",
49+
"eslint-config-prettier": "^2.3.0",
4950
"eslint-plugin-import": "^2.1.0",
50-
"eslint-plugin-jsx-a11y": "^4.0.0",
51-
"eslint-plugin-react": "^6.10.3",
52-
"webpack": "^2.4.1"
51+
"eslint-plugin-jsx-a11y": "^5.1.1",
52+
"eslint-plugin-prettier": "^2.2.0",
53+
"eslint-plugin-react": "^7.2.1",
54+
"prettier": "^1.5.3",
55+
"webpack": "^3.5.5"
5356
},
5457
"dependencies": {
55-
"detect-it": "^3.0.0",
58+
"detect-it": "^3.0.1",
5659
"object-assign": "^4.1.1",
5760
"prop-types": "^15.5.8"
5861
}

src/compareProps.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@ export default function compareProps(propsA, propsB) {
1919
// forceState is handled in componentWillReceiveProps
2020
const nextPOffset = propsB.forceState ? -1 : 0;
2121
const pOffset = propsA.forceState ? -1 : 0;
22-
if ((keysB.length + nextPOffset) !== (Object.keys(propsA).length + pOffset)) return false;
22+
if (keysB.length + nextPOffset !== Object.keys(propsA).length + pOffset)
23+
return false;
2324

2425
// if it's an state prop options object, then shallow compare the options for equality
25-
const sameStateProp = (stateProp) => {
26+
const sameStateProp = stateProp => {
2627
// if propsB doesn't have any of the options object keys, then return false b/c not options obj
2728
if (!statePropOptionKeys.some(key => propsB[stateProp][key])) return false;
2829
// shallow compare the options for equality
29-
return statePropOptionKeys.every(key => propsB[stateProp][key] === propsA[stateProp][key]);
30+
return statePropOptionKeys.every(
31+
key => propsB[stateProp][key] === propsA[stateProp][key],
32+
);
3033
};
3134

3235
// loop through props
@@ -38,7 +41,10 @@ export default function compareProps(propsA, propsB) {
3841
// if the two props aren't equal, do some additional checks before returning false
3942
if (propsB[keysB[i]] !== propsA[keysB[i]]) {
4043
if (keysB[i] === 'as') {
41-
if (React.isValidElement(propsA.as) && React.isValidElement(propsB.as)) {
44+
if (
45+
React.isValidElement(propsA.as) &&
46+
React.isValidElement(propsB.as)
47+
) {
4248
// If `as` is JSX/ReactElement, first check to see if `as.type` is the same,
4349
// e.g. 'div', 'span', ReactClass, ReactFunctionalComponent, and then shallowly
4450
// compare it's props with a recursive call to sameProps - this should only recurse

src/constants.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,20 @@ export const knownRoleTags = {
6464

6565
// elements triggered by the enter key
6666
export function enterKeyTrigger(tag, type) {
67-
return (tag !== 'select') && (tag !== 'input' || (type !== 'checkbox' && type !== 'radio'));
67+
return (
68+
tag !== 'select' &&
69+
(tag !== 'input' || (type !== 'checkbox' && type !== 'radio'))
70+
);
6871
}
6972

7073
// elements triggered by the space bar
7174
export function spaceKeyTrigger(tag, type) {
72-
return (tag === 'button') || (tag === 'select') ||
73-
(tag === 'input' && (type === 'checkbox' || type === 'radio' || type === 'submit'));
75+
return (
76+
tag === 'button' ||
77+
tag === 'select' ||
78+
(tag === 'input' &&
79+
(type === 'checkbox' || type === 'radio' || type === 'submit'))
80+
);
7481
}
7582

7683
// known props to not pass through, every prop not on this list is passed through
@@ -86,6 +93,7 @@ export const knownProps = {
8693
onTapTwo: true,
8794
onTapThree: true,
8895
onTapFour: true,
96+
onLongPress: true,
8997
onMouseEnter: true,
9098
onMouseLeave: true,
9199
onMouseMove: true,
@@ -116,6 +124,8 @@ export const knownProps = {
116124
// ms to allow for the browser to add subsequent event to the queue in setTimeouts
117125
export const queueTime = 600;
118126

127+
export const defaultTapTimeCutoff = 500;
128+
119129
export function dummyEvent(type) {
120130
return {
121131
type,

src/extractStyle.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { statePropOptionKeys } from './constants';
33
// extract and return the style object and className string for the state given
44
export function extractStyle(props, state) {
55
// if no hoverActive prop, then use hover prop for style and classes
6-
let stateProp = (state === 'hoverActive' && !props.hoverActive) ? 'hover' : state;
6+
let stateProp =
7+
state === 'hoverActive' && !props.hoverActive ? 'hover' : state;
78
// loop until the state prop to use is found (i.e. it's not a string)
89
let times = 0;
910
while (typeof stateProp === 'string' && times < 10) {
@@ -45,7 +46,7 @@ export function setActiveAndFocusProps(props) {
4546

4647
export function joinClasses(className, iStateClass, focusClass) {
4748
let joined = className;
48-
joined += (joined && iStateClass) ? ` ${iStateClass}` : `${iStateClass}`;
49-
joined += (joined && focusClass) ? ` ${focusClass}` : `${focusClass}`;
49+
joined += joined && iStateClass ? ` ${iStateClass}` : `${iStateClass}`;
50+
joined += joined && focusClass ? ` ${focusClass}` : `${focusClass}`;
5051
return joined;
5152
}

0 commit comments

Comments
 (0)