[MM-9454] Added fade to send button (#2677)

* [MM-9454] Added jest-enzyme to devDependencies

* [MM-9454] Refactored SendButton as component

* [MM-9454] Added fade to SendButton

* [MM-9454] Changed Fade to PureComponent
This commit is contained in:
Courtney Pattison 2019-04-29 07:54:00 -07:00 committed by Miguel Alatzar
parent b3a586fd57
commit ce5c30e9ca
10 changed files with 604 additions and 117 deletions

6
app/components/__mocks__/react.js vendored Normal file
View file

@ -0,0 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as React from 'react';
module.exports = {...React, memo: (x) => x};

View file

@ -0,0 +1,39 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Fade should render {opacity: 0} 1`] = `
<AnimatedComponent
style={
Object {
"opacity": 0,
"transform": Array [
Object {
"scale": 0,
},
],
}
}
>
<Text>
text
</Text>
</AnimatedComponent>
`;
exports[`Fade should render {opacity: 1} 1`] = `
<AnimatedComponent
style={
Object {
"opacity": 1,
"transform": Array [
Object {
"scale": 1,
},
],
}
}
>
<Text>
text
</Text>
</AnimatedComponent>
`;

View file

@ -0,0 +1,103 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SendButton should change theme backgroundColor to 0.3 opacity 1`] = `
<View
style={
Object {
"justifyContent": "flex-end",
"paddingHorizontal": 5,
"paddingVertical": 3,
}
}
>
<View
style={
Array [
Object {
"alignItems": "center",
"backgroundColor": "#166de0",
"borderRadius": 18,
"height": 28,
"justifyContent": "center",
"width": 28,
},
Object {
"backgroundColor": "rgba(22,109,224,0.3)",
},
]
}
>
<PaperPlane
color="#ffffff"
height={13}
width={15}
/>
</View>
</View>
`;
exports[`SendButton should match snapshot 1`] = `
<TouchableOpacity
activeOpacity={0.2}
onPress={[MockFunction]}
style={
Object {
"justifyContent": "flex-end",
"paddingHorizontal": 5,
"paddingVertical": 3,
}
}
>
<View
style={
Object {
"alignItems": "center",
"backgroundColor": "#166de0",
"borderRadius": 18,
"height": 28,
"justifyContent": "center",
"width": 28,
}
}
>
<PaperPlane
color="#ffffff"
height={13}
width={15}
/>
</View>
</TouchableOpacity>
`;
exports[`SendButton should render theme backgroundColor 1`] = `
<TouchableOpacity
activeOpacity={0.2}
onPress={[MockFunction]}
style={
Object {
"justifyContent": "flex-end",
"paddingHorizontal": 5,
"paddingVertical": 3,
}
}
>
<View
style={
Object {
"alignItems": "center",
"backgroundColor": "#166de0",
"borderRadius": 18,
"height": 28,
"justifyContent": "center",
"width": 28,
}
}
>
<PaperPlane
color="#ffffff"
height={13}
width={15}
/>
</View>
</TouchableOpacity>
`;

51
app/components/fade.js Normal file
View file

@ -0,0 +1,51 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Animated} from 'react-native';
export const FADE_DURATION = 300;
export default class Fade extends PureComponent {
static propTypes = {
children: PropTypes.node.isRequired,
style: PropTypes.object,
visible: PropTypes.bool.isRequired,
};
constructor(props) {
super(props);
this.state = {
fadeAnim: new Animated.Value(props.visible ? 1 : 0),
};
}
componentDidUpdate(prevProps) {
if (prevProps.visible !== this.props.visible) {
Animated.timing(
this.state.fadeAnim,
{
toValue: prevProps.visible ? 0 : 1,
duration: FADE_DURATION,
}
).start();
}
}
render() {
const {fadeAnim} = this.state;
return (
<Animated.View
style={{
...this.props.style,
opacity: fadeAnim,
transform: [{scale: fadeAnim}],
}}
>
{this.props.children}
</Animated.View>
);
}
}

View file

@ -0,0 +1,78 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Animated, Text} from 'react-native';
import {shallow} from 'enzyme';
import Fade, {FADE_DURATION} from './fade';
jest.useFakeTimers();
describe('Fade', () => {
const baseProps = {
visible: true,
disabled: true,
};
function getWrapper(props = {}) {
const dummyText = 'text';
return shallow(
<Fade
{...baseProps}
{...props}
>
<Text>{dummyText}</Text>
</Fade>
);
}
function getAnimValue(begin, end) {
const animValue = new Animated.Value(begin);
animValue.setValue(end);
animValue.stopTracking();
return animValue;
}
test('should render {opacity: 1}', () => {
const wrapper = getWrapper({visible: true});
expect(wrapper.getElement()).toMatchSnapshot();
expect(wrapper).toHaveStyle('opacity', new Animated.Value(1));
});
test('should render {opacity: 0}', () => {
const wrapper = getWrapper({visible: false});
expect(wrapper.getElement()).toMatchSnapshot();
expect(wrapper).toHaveStyle('opacity', new Animated.Value(0));
});
test('should change opacity from 1 to 0', () => {
const wrapper = getWrapper({visible: true});
expect(wrapper).toHaveStyle('opacity', new Animated.Value(1));
wrapper.setProps({visible: false});
jest.advanceTimersByTime(FADE_DURATION);
expect(wrapper).toHaveStyle('opacity', getAnimValue(1, 0));
});
test('should not change opacity when disabled flag is switched', () => {
const wrapper = getWrapper({disabled: false});
expect(wrapper).toHaveStyle('opacity', new Animated.Value(1));
wrapper.setProps({disabled: true});
expect(wrapper).toHaveStyle('opacity', new Animated.Value(1));
});
test('should not change opacity when props stay the same', () => {
const wrapper = getWrapper({visible: true});
expect(wrapper).toHaveStyle('opacity', new Animated.Value(1));
wrapper.setProps({visible: true});
expect(wrapper).toHaveStyle('opacity', new Animated.Value(1));
});
});

View file

@ -3,7 +3,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Alert, BackHandler, Keyboard, Platform, Text, TextInput, TouchableOpacity, View} from 'react-native';
import {Alert, BackHandler, Keyboard, Platform, Text, TextInput, View} from 'react-native';
import {intlShape} from 'react-intl';
import Button from 'react-native-button';
import {General, RequestStatus} from 'mattermost-redux/constants';
@ -12,6 +12,7 @@ import {getFormattedFileSize} from 'mattermost-redux/utils/file_utils';
import AttachmentButton from 'app/components/attachment_button';
import Autocomplete from 'app/components/autocomplete';
import Fade from 'app/components/fade';
import FileUploadPreview from 'app/components/file_upload_preview';
import {INITIAL_HEIGHT, INSERT_TO_COMMENT, INSERT_TO_DRAFT, IS_REACTION_REGEX, MAX_CONTENT_HEIGHT, MAX_FILE_COUNT} from 'app/constants/post_textbox';
import {confirmOutOfOfficeDisabled} from 'app/utils/status';
@ -19,14 +20,13 @@ import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
import FormattedMarkdownText from 'app/components/formatted_markdown_text';
import FormattedText from 'app/components/formatted_text';
import SendButton from 'app/components/send_button';
import Typing from './components/typing';
const AUTOCOMPLETE_MARGIN = 20;
const AUTOCOMPLETE_MAX_HEIGHT = 200;
let PaperPlane = null;
export default class PostTextbox extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
@ -122,21 +122,19 @@ export default class PostTextbox extends PureComponent {
canSend = () => {
const {files, maxMessageLength, uploadFileRequestStatus} = this.props;
const {value} = this.state;
const valueLength = value.trim().length;
const messageLength = value.trim().length;
if (files.length) {
const filesLoading = [];
files.forEach((file) => {
if (file.loading) {
filesLoading.push(file);
}
});
const loadingComplete = filesLoading.length === 0;
return valueLength <= maxMessageLength && uploadFileRequestStatus !== RequestStatus.STARTED && loadingComplete;
if (messageLength > maxMessageLength) {
return false;
}
return valueLength > 0 && valueLength <= maxMessageLength;
if (files.length) {
const loadingComplete = !this.isFileLoading();
const alreadySendingFiles = uploadFileRequestStatus === RequestStatus.STARTED;
return loadingComplete && !alreadySendingFiles;
}
return messageLength > 0;
};
changeDraft = (text) => {
@ -294,52 +292,15 @@ export default class PostTextbox extends PureComponent {
this.props.actions.initUploadFiles(images, this.props.rootId);
};
renderSendButton = () => {
const {files, theme} = this.props;
const style = getStyleSheet(theme);
isFileLoading() {
const {files} = this.props;
const canSend = this.canSend();
const imagesLoading = files.filter((f) => f.loading).length > 0;
return files.some((file) => file.loading);
}
let button = null;
if (canSend || imagesLoading) {
if (!PaperPlane) {
PaperPlane = require('app/components/paper_plane').default;
}
const icon = (
<PaperPlane
height={13}
width={15}
color={theme.buttonColor}
/>
);
if (imagesLoading) {
button = (
<View style={style.sendButtonContainer}>
<View style={[style.sendButton, style.disableButton]}>
{icon}
</View>
</View>
);
} else if (canSend) {
button = (
<TouchableOpacity
onPress={this.handleSendMessage}
style={style.sendButtonContainer}
>
<View style={style.sendButton}>
{icon}
</View>
</TouchableOpacity>
);
}
}
return button;
};
isSendButtonVisible() {
return this.canSend() || this.isFileLoading();
}
sendMessage = () => {
const {actions, currentUserId, channelId, files, rootId} = this.props;
@ -644,7 +605,13 @@ export default class PostTextbox extends PureComponent {
disableFullscreenUI={true}
editable={!channelIsReadOnly}
/>
{this.renderSendButton()}
<Fade visible={this.isSendButtonVisible()}>
<SendButton
disabled={this.isFileLoading()}
handleSendMessage={this.handleSendMessage}
theme={theme}
/>
</Fade>
</View>
</View>
)}
@ -656,9 +623,6 @@ export default class PostTextbox extends PureComponent {
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
disableButton: {
backgroundColor: changeOpacity(theme.buttonBg, 0.3),
},
input: {
color: '#000',
flex: 1,
@ -708,19 +672,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
marginLeft: 10,
marginRight: 10,
},
sendButtonContainer: {
justifyContent: 'flex-end',
paddingHorizontal: 5,
paddingVertical: 3,
},
sendButton: {
backgroundColor: theme.buttonBg,
borderRadius: 18,
height: 28,
width: 28,
alignItems: 'center',
justifyContent: 'center',
},
archivedWrapper: {
paddingLeft: 20,
paddingRight: 20,

View file

@ -0,0 +1,78 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {memo} from 'react';
import {TouchableOpacity, View} from 'react-native';
import PropTypes from 'prop-types';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
let PaperPlane = null;
function SendButton(props) {
const {theme} = props;
const style = getStyleSheet(theme);
if (!PaperPlane) {
PaperPlane = require('app/components/paper_plane').default;
}
const icon = (
<PaperPlane
height={13}
width={15}
color={theme.buttonColor}
/>
);
if (props.disabled) {
return (
<View style={style.sendButtonContainer}>
<View style={[style.sendButton, style.disableButton]}>
{icon}
</View>
</View>
);
}
return (
<TouchableOpacity
onPress={props.handleSendMessage}
style={style.sendButtonContainer}
>
<View style={style.sendButton}>
{icon}
</View>
</TouchableOpacity>
);
}
SendButton.propTypes = {
handleSendMessage: PropTypes.func.isRequired,
disabled: PropTypes.bool.isRequired,
theme: PropTypes.object.isRequired,
};
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
disableButton: {
backgroundColor: changeOpacity(theme.buttonBg, 0.3),
},
sendButtonContainer: {
justifyContent: 'flex-end',
paddingHorizontal: 5,
paddingVertical: 3,
},
sendButton: {
backgroundColor: theme.buttonBg,
borderRadius: 18,
height: 28,
width: 28,
alignItems: 'center',
justifyContent: 'center',
},
};
});
export default memo(SendButton);

View file

@ -0,0 +1,47 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {shallow} from 'enzyme';
import Preferences from 'mattermost-redux/constants/preferences';
import SendButton from 'app/components/send_button';
import {changeOpacity} from 'app/utils/theme';
describe('SendButton', () => {
const baseProps = {
theme: Preferences.THEMES.default,
handleSendMessage: jest.fn(),
disabled: false,
};
function getWrapper(props = {}) {
return shallow(
<SendButton
{...baseProps}
{...props}
/>
);
}
test('should match snapshot', () => {
const wrapper = getWrapper();
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should render theme backgroundColor', () => {
const wrapper = getWrapper();
expect(wrapper.getElement()).toMatchSnapshot();
expect(wrapper.childAt(0)).toHaveStyle('backgroundColor', baseProps.theme.buttonBg);
});
test('should change theme backgroundColor to 0.3 opacity', () => {
const wrapper = getWrapper({disabled: true});
expect(wrapper.getElement()).toMatchSnapshot();
expect(wrapper.childAt(0)).toHaveStyle('backgroundColor', changeOpacity(baseProps.theme.buttonBg, 0.3));
});
});

212
package-lock.json generated
View file

@ -1974,7 +1974,7 @@
},
"array-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
"dev": true
},
@ -2700,6 +2700,7 @@
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
@ -2744,7 +2745,8 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true
"dev": true,
"optional": true
},
"is-glob": {
"version": "4.0.0",
@ -2798,6 +2800,12 @@
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
"dev": true
},
"circular-json-es6": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/circular-json-es6/-/circular-json-es6-2.0.2.tgz",
"integrity": "sha512-ODYONMMNb3p658Zv+Pp+/XPa5s6q7afhz3Tzyvo+VRh9WIrJ64J76ZC4GQxnlye/NesTn09jvOiuE8+xxfpwhQ==",
"dev": true
},
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@ -3110,7 +3118,7 @@
"dependencies": {
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"fbjs": {
@ -3141,7 +3149,7 @@
},
"css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
"dev": true,
"requires": {
@ -3228,6 +3236,27 @@
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
},
"deep-equal-ident": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal-ident/-/deep-equal-ident-1.1.1.tgz",
"integrity": "sha1-BvS4nlNxDNbOpKd4HHqVZkLejck=",
"dev": true,
"requires": {
"lodash.isequal": "^3.0"
},
"dependencies": {
"lodash.isequal": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-3.0.4.tgz",
"integrity": "sha1-HDXrO27wzR/1F0Pj6jz3/f/ay2Q=",
"dev": true,
"requires": {
"lodash._baseisequal": "^3.0.0",
"lodash._bindcallback": "^3.0.0"
}
}
}
},
"deep-freeze": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz",
@ -3564,6 +3593,16 @@
"semver": "^5.6.0"
}
},
"enzyme-matchers": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/enzyme-matchers/-/enzyme-matchers-7.0.2.tgz",
"integrity": "sha512-hsWb4Mw+F0eJ9q6ljTK2RqLwsrdoKfr5IXmKtDaTPeOEFXsVl6L2RX2REdevvn2KJfSxkcKaCGwPldOSc1l9tQ==",
"dev": true,
"requires": {
"circular-json-es6": "^2.0.1",
"deep-equal-ident": "^1.1.1"
}
},
"enzyme-to-json": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.3.5.tgz",
@ -4131,7 +4170,7 @@
},
"external-editor": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"requires": {
"chardet": "^0.4.0",
@ -4322,7 +4361,7 @@
"dependencies": {
"json5": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
}
@ -4784,7 +4823,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -4802,11 +4842,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -4819,15 +4861,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -4930,7 +4975,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -4940,6 +4986,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -4952,17 +4999,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -4979,6 +5029,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -5051,7 +5102,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -5061,6 +5113,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -5136,7 +5189,8 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -5166,6 +5220,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -5183,6 +5238,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -5221,11 +5277,13 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true
"bundled": true,
"optional": true
}
}
},
@ -7393,6 +7451,15 @@
}
}
},
"jest-environment-enzyme": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/jest-environment-enzyme/-/jest-environment-enzyme-7.0.2.tgz",
"integrity": "sha512-cBBWX3ZCR4JJR6ml6cTYLH1fdBZ2QEbywY6yrkgTP6OZgE+Nh6Agu0g99uJha2F36+zRFS/xkk8AIEAJvLtzQQ==",
"dev": true,
"requires": {
"jest-environment-jsdom": "^24.0.0"
}
},
"jest-environment-jsdom": {
"version": "24.0.0",
"resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.0.0.tgz",
@ -7414,6 +7481,17 @@
"jest-util": "^24.0.0"
}
},
"jest-enzyme": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/jest-enzyme/-/jest-enzyme-7.0.2.tgz",
"integrity": "sha512-7N9YhFmyPkDcVyvifyWePkJaZQX/wON4D6uD8qmGSc2ZaXjj+fkEPMaZ1+Kqnp75FTHaJZ+NVigpmoQiys+J2w==",
"dev": true,
"requires": {
"enzyme-matchers": "^7.0.2",
"enzyme-to-json": "^3.3.0",
"jest-environment-enzyme": "^7.0.2"
}
},
"jest-get-type": {
"version": "24.0.0",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.0.0.tgz",
@ -9479,7 +9557,7 @@
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"requires": {
"graceful-fs": "^4.1.2",
@ -9539,6 +9617,29 @@
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.11.tgz",
"integrity": "sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q=="
},
"lodash._baseisequal": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz",
"integrity": "sha1-2AJfdjOdKTQnZ9zIh85cuVpbUfE=",
"dev": true,
"requires": {
"lodash.isarray": "^3.0.0",
"lodash.istypedarray": "^3.0.0",
"lodash.keys": "^3.0.0"
}
},
"lodash._bindcallback": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz",
"integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=",
"dev": true
},
"lodash._getnative": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
"integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
"dev": true
},
"lodash.assign": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
@ -9577,6 +9678,18 @@
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=",
"dev": true
},
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
"dev": true
},
"lodash.isarray": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
"integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
"dev": true
},
"lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
@ -9585,7 +9698,7 @@
},
"lodash.isempty": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
"resolved": "http://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
"integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4="
},
"lodash.isequal": {
@ -9616,6 +9729,23 @@
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
"dev": true
},
"lodash.istypedarray": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz",
"integrity": "sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I=",
"dev": true
},
"lodash.keys": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
"integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
"dev": true,
"requires": {
"lodash._getnative": "^3.0.0",
"lodash.isarguments": "^3.0.0",
"lodash.isarray": "^3.0.0"
}
},
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@ -10160,7 +10290,7 @@
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mixin-deep": {
@ -10184,7 +10314,7 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
@ -10192,7 +10322,7 @@
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
@ -11841,7 +11971,7 @@
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
},
"wordwrap": {
@ -11896,14 +12026,14 @@
},
"get-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
}
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"output-file-sync": {
@ -12049,7 +12179,7 @@
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-is-inside": {
@ -12099,7 +12229,7 @@
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
},
"pirates": {
@ -12825,7 +12955,7 @@
"dependencies": {
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"fbjs": {
@ -12990,7 +13120,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
@ -13025,7 +13155,8 @@
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
"dev": true
"dev": true,
"optional": true
},
"braces": {
"version": "2.3.2",
@ -13311,7 +13442,8 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true
"dev": true,
"optional": true
},
"micromatch": {
"version": "3.1.10",
@ -13988,7 +14120,7 @@
},
"safe-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
"requires": {
"ret": "~0.1.10"
@ -14337,7 +14469,7 @@
"dependencies": {
"async": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.0.0.tgz",
"resolved": "http://registry.npmjs.org/async/-/async-2.0.0.tgz",
"integrity": "sha1-0JAK04WvE4BFQKEJxCFm4657K50=",
"dev": true,
"requires": {
@ -14436,7 +14568,7 @@
},
"serialize-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
"resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
"integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go="
},
"serve-static": {
@ -14557,7 +14689,7 @@
},
"xmlbuilder": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
"resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
"integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M="
}
}
@ -14779,7 +14911,7 @@
},
"inquirer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz",
"resolved": "http://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz",
"integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==",
"dev": true,
"requires": {
@ -15182,7 +15314,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
@ -15195,7 +15327,7 @@
},
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
},
"strip-json-comments": {
@ -15400,7 +15532,7 @@
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"through2": {
@ -16141,7 +16273,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
"string-width": "^1.0.1",

View file

@ -93,6 +93,7 @@
"eslint-plugin-react": "7.12.4",
"jest": "24.1.0",
"jest-cli": "24.1.0",
"jest-enzyme": "7.0.2",
"jsdom-global": "3.0.2",
"metro-react-native-babel-preset": "0.51.1",
"mmjstool": "github:mattermost/mattermost-utilities",
@ -130,7 +131,8 @@
],
"preset": "react-native",
"setupFilesAfterEnv": [
"<rootDir>/test/setup.js"
"<rootDir>/test/setup.js",
"<rootDir>/node_modules/jest-enzyme/lib/index.js"
],
"testPathIgnorePatterns": [
"/node_modules/"