diff --git a/flow-typed/npm/react-transition-group_v2.x.x.js b/flow-typed/npm/react-transition-group_v2.x.x.js new file mode 100644 index 000000000..8b885c368 --- /dev/null +++ b/flow-typed/npm/react-transition-group_v2.x.x.js @@ -0,0 +1,68 @@ +// flow-typed signature: 896bbb51b1a943fefff583786cd4d0c0 +// flow-typed version: b6c24caf38/react-transition-group_v2.x.x/flow_>=v0.60.x + +// @flow + +declare module 'react-transition-group' { + declare export type CSSTransitionClassNames = { + appear?: string, + appearActive?: string, + enter?: string, + enterActive?: string, + enterDone?: string, + exit?: string, + exitActive?: string, + exitDone?: string, + }; + + declare export type TransitionStatus = 'entering' | 'entered' | 'exiting' | 'exited' | 'unmounted'; + + declare export type EndHandler = (node: HTMLElement, done: () => void) => void; + declare export type EnterHandler = (node: HTMLElement, isAppearing: boolean) => void; + declare export type ExitHandler = (node: HTMLElement) => void; + + declare type TransitionActions = { + appear?: boolean; + enter?: boolean; + exit?: boolean; + } + + declare type TransitionProps = TransitionActions & { + mountOnEnter?: boolean, + unmountOnExit?: boolean, + onEnter?: EnterHandler, + onEntering?: EnterHandler, + onEntered?: EnterHandler, + onExit?: ExitHandler, + onExiting?: ExitHandler, + onExited?: ExitHandler, + } & ({ + timeout: number | { enter?: number, exit?: number }, + addEndListener?: null, + } | { + timeout?: number | { enter?: number, exit?: number }, + addEndListener: EndHandler, + }) + + declare export class Transition extends React$Component React$Node) | React$Node, + }> {} + + declare export class TransitionGroup extends React$Component React$Node, + }> {} + + declare export class ReplaceTransition extends React$Component {} + + declare export class CSSTransition extends React$Component React$Node) | React$Node, + }> {} +} diff --git a/package.json b/package.json index ce60e846e..eecacea65 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "react-emotion": "^9.2.6", "react-redux": "^5.0.7", "react-test-renderer": "^16.5.2", + "react-transition-group": "^2.5.1", "react-virtualized-auto-sizer": "^1.0.2", "react-window": "^1.3.1", "redux": "^4.0.0", diff --git a/src/App.js b/src/App.js index 6b8d15dae..3944bd46d 100644 --- a/src/App.js +++ b/src/App.js @@ -8,7 +8,6 @@ import React from 'react'; import {FlexColumn, FlexRow} from 'flipper'; import {connect} from 'react-redux'; -import {toggleBugDialogVisible} from './reducers/application.js'; import WelcomeScreen from './chrome/WelcomeScreen.js'; import TitleBar from './chrome/TitleBar.js'; import MainSidebar from './chrome/MainSidebar.js'; @@ -25,11 +24,9 @@ type Props = { logger: Logger, bugReporter: BugReporter, leftSidebarVisible: boolean, - bugDialogVisible: boolean, pluginManagerVisible: boolean, selectedDevice: ?BaseDevice, error: ?string, - toggleBugDialogVisible: (visible?: boolean) => any, }; export class App extends React.Component { @@ -51,14 +48,7 @@ export class App extends React.Component { return ( - {this.props.bugDialogVisible && ( - { - this.props.toggleBugDialogVisible(false); - }} - /> - )} + {this.props.leftSidebarVisible && } {this.props.selectedDevice ? ( @@ -78,16 +68,12 @@ export class App extends React.Component { * run Flow. */ export default connect( ({ - application: {pluginManagerVisible, bugDialogVisible, leftSidebarVisible}, + application: {pluginManagerVisible, leftSidebarVisible}, connections: {selectedDevice, error}, }) => ({ pluginManagerVisible, - bugDialogVisible, leftSidebarVisible, selectedDevice, error, }), - { - toggleBugDialogVisible, - }, )(App); diff --git a/src/__tests__/__snapshots__/App.electron.js.snap b/src/__tests__/__snapshots__/App.electron.js.snap index 98b16f9cf..34b974c19 100644 --- a/src/__tests__/__snapshots__/App.electron.js.snap +++ b/src/__tests__/__snapshots__/App.electron.js.snap @@ -5,7 +5,7 @@ exports[`Empty app state matches snapshot 1`] = ` className="css-1si6n3e" >
({ + transform: `translateY(${ + state === 'entering' || state === 'exiting' ? '-110' : '' + }%)`, + transition: '.3s transform', width: 400, height: 300, position: 'absolute', left: '50%', marginLeft: -200, - top: 40, - zIndex: 999999, - backgroundColor: '#fff', - border: '1px solid #ddd', + top: 38, + zIndex: 2, + backgroundColor: '#EFEEEF', + border: '1px solid #C6C6C6', borderTop: 'none', - borderBottomLeftRadius: 5, - borderBottomRightRadius: 5, - boxShadow: '0 1px 10px rgba(0, 0, 0, 0.1)', -}); + borderBottomLeftRadius: 2, + borderBottomRightRadius: 2, + boxShadow: '0 5px 13px rgba(0, 0, 0, 0.2)', +})); const TitleInput = styled(Input)({ ...textareaStyle, @@ -64,47 +92,56 @@ const Footer = styled(FlexRow)({ }); const CloseDoneButton = styled(Button)({ - width: 50, - margin: '10px auto', + marginTop: 20, + marginLeft: 'auto !important', + marginRight: 'auto', }); -type State = { +const InfoBox = styled(FlexRow)({ + marginBottom: 20, + lineHeight: '130%', +}); + +type State = {| description: string, title: string, submitting: boolean, - success: false | number, // false if not created, id of bug if it's been created + success: ?number, error: ?string, -}; +|}; -type Props = { +type Props = {| bugReporter: BugReporter, - close: () => void, -}; + toggleBugDialogVisible: (visible: boolean) => mixed, + activePlugin: ?Class | FlipperDevicePlugin<>>, + bugDialogVisible: boolean, +|}; -const DEFAULT_DESCRIPTION = `Thanks for taking the time to provide feedback! -Please fill out the following information to make addressing your issue easier. - -What device platform are you using? ios/android -What sort of device are you using? emulator/physical -What app are you trying to use? wilde, fb4a, lite etc -Describe your problem in as much detail as possible: `; - -export default class BugReporterDialog extends Component { - constructor(props: Props) { - super(props); - - this.state = { - description: DEFAULT_DESCRIPTION, - title: '', - submitting: false, - success: false, - error: null, - }; - } +class BugReporterDialog extends Component { + state = { + description: '', + title: '', + submitting: false, + success: null, + error: null, + }; titleRef: HTMLElement; descriptionRef: HTMLElement; + componentDidMount() { + document.addEventListener('keydown', this.onKeyDown); + } + componentWillUnmount() { + document.removeEventListener('keydown', this.onKeyDown); + } + + onKeyDown = (e: KeyboardEvent) => { + if (this.props.bugDialogVisible && e.key === 'Escape') { + this.onCancel(); + } + }; + onDescriptionChange = (e: SyntheticInputEvent) => { this.setState({description: e.target.value}); }; @@ -173,67 +210,142 @@ export default class BugReporterDialog extends Component { }; onCancel = () => { - this.props.close(); + this.setState({ + error: null, + title: '', + description: '', + }); + this.props.toggleBugDialogVisible(false); }; render() { let content; - - const {title, success, error, description} = this.state; + const {title, success, error, description, submitting} = this.state; if (success) { content = ( - - Bug - - - - {success} - - - - created. Thank you for the report! - - - Close +
+ +
+ Bug Report created + The bug report{' '} + + {success} + {' '} + was successfully created. Thank you for your help making Flipper + better! +
+ + Close +
); } else { content = ( + Report a bug... + {this.props.activePlugin?.bugs && ( + + + + If you bug is related to the{' '} + + {this.props.activePlugin?.title || + this.props.activePlugin?.id}{' '} + plugin + + {this.props.activePlugin?.bugs?.url && ( + + , you might find useful information about it here:{' '} + + {this.props.activePlugin?.bugs?.url} + + + )} + {this.props.activePlugin?.bugs?.email && ( + + , you might also want contact{' '} + + {this.props.activePlugin?.bugs?.email} + , the author/oncall of this plugin, directly + + )} + . + + + )}
{error != null && {error}} - - +
); } - return {content}; + return ( + + {state => {content}} + + ); } } + +// $FlowFixMe +export default connect( + ({ + plugins: {devicePlugins, clientPlugins}, + connections: {selectedPlugin}, + application: {bugDialogVisible}, + }) => ({ + bugDialogVisible, + activePlugin: + devicePlugins.get(selectedPlugin) || clientPlugins.get(selectedPlugin), + }), + { + toggleBugDialogVisible, + }, +)(BugReporterDialog); diff --git a/src/chrome/TitleBar.js b/src/chrome/TitleBar.js index 72220ac6b..6519ef139 100644 --- a/src/chrome/TitleBar.js +++ b/src/chrome/TitleBar.js @@ -44,6 +44,7 @@ const AppTitleBar = styled(FlexRow)(({focused}) => ({ paddingRight: 10, justifyContent: 'space-between', WebkitAppRegion: 'drag', + zIndex: 3, })); type Props = {| diff --git a/yarn.lock b/yarn.lock index f7bcddc43..66a58c2ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -62,7 +62,7 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/runtime@^7.0.0": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f" integrity sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg== @@ -2054,6 +2054,13 @@ doctrine@^2.0.2, doctrine@^2.1.0: dependencies: esutils "^2.0.2" +dom-helpers@^3.3.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" + integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== + dependencies: + "@babel/runtime" "^7.1.2" + domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -4021,7 +4028,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -4292,6 +4299,13 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: dependencies: js-tokens "^3.0.0" +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -5283,6 +5297,11 @@ react-is@^16.5.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.5.2.tgz#e2a7b7c3f5d48062eb769fcb123505eb928722e3" integrity sha512-hSl7E6l25GTjNEZATqZIuWOgSnpXb3kD0DVCujmg46K5zLxsbiKaaT6VO9slkSBDPZfYs30lwfJwbOFOnoEnKQ== +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + react-redux@^5.0.7: version "5.0.7" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8" @@ -5304,6 +5323,16 @@ react-test-renderer@^16.5.2: react-is "^16.5.2" schedule "^0.5.0" +react-transition-group@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.5.1.tgz#67fbd8d30ebb1c57a149d554dbb82eabefa61f0d" + integrity sha512-8x/CxUL9SjYFmUdzsBPTgtKeCxt7QArjNSte0wwiLtF/Ix/o1nWNJooNy5o9XbHIKS31pz7J5VF2l41TwlvbHQ== + dependencies: + dom-helpers "^3.3.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react-lifecycles-compat "^3.0.4" + react-virtualized-auto-sizer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"