fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
/* eslint react/sort-comp: 0 */
|
|
|
|
import _ from 'underscore';
|
|
|
|
import React from 'react';
|
|
|
|
import {remote} from 'electron';
|
|
|
|
|
|
|
|
import {
|
2016-04-05 09:21:39 +08:00
|
|
|
Message,
|
2016-04-23 08:39:29 +08:00
|
|
|
Actions,
|
2016-04-05 09:21:39 +08:00
|
|
|
DraftStore,
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
ComponentRegistry,
|
|
|
|
WorkspaceStore,
|
|
|
|
} from 'nylas-exports';
|
|
|
|
import ComposeButton from './compose-button';
|
|
|
|
import ComposerView from './composer-view';
|
|
|
|
|
|
|
|
import InflateDraftClientId from './decorators/inflate-draft-client-id';
|
2016-04-05 08:12:59 +08:00
|
|
|
const ComposerViewForDraftClientId = InflateDraftClientId(ComposerView);
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
|
|
|
|
class ComposerWithWindowProps extends React.Component {
|
|
|
|
static displayName = 'ComposerWithWindowProps';
|
|
|
|
static containerRequired = false;
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
2016-04-23 04:30:42 +08:00
|
|
|
// We'll now always have windowProps by the time we construct this.
|
2016-04-30 05:30:25 +08:00
|
|
|
const windowProps = NylasEnv.getWindowProps();
|
2016-04-23 04:30:42 +08:00
|
|
|
const {draftJSON, draftClientId} = windowProps;
|
2016-04-27 04:01:39 +08:00
|
|
|
if (!draftJSON) {
|
|
|
|
throw new Error("Initialize popout composer windows with valid draftJSON")
|
|
|
|
}
|
2016-04-23 04:30:42 +08:00
|
|
|
const draft = new Message().fromJSON(draftJSON);
|
|
|
|
DraftStore._createSession(draftClientId, draft);
|
|
|
|
this.state = windowProps
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
|
2016-04-30 05:30:25 +08:00
|
|
|
componentWillUnmount() {
|
|
|
|
if (this._usub) {this._usub()}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
this.refs.composer.focus()
|
|
|
|
}
|
|
|
|
|
|
|
|
_onDraftReady = () => {
|
2016-04-05 09:21:39 +08:00
|
|
|
this.refs.composer.focus().then(() => {
|
2016-04-23 08:39:29 +08:00
|
|
|
NylasEnv.displayWindow();
|
2016-04-30 05:30:25 +08:00
|
|
|
|
2016-04-23 04:30:42 +08:00
|
|
|
if (this.state.errorMessage) {
|
|
|
|
this._showInitialErrorDialog(this.state.errorMessage);
|
|
|
|
}
|
|
|
|
|
2016-04-30 05:30:25 +08:00
|
|
|
// This will start loading the rest of the composer's plugins. This
|
|
|
|
// may take a while (hundreds of ms) depending on how many plugins
|
|
|
|
// you have installed. For some reason it takes two frames to
|
|
|
|
// reliably get the basic composer (Send button, etc) painted
|
|
|
|
// properly.
|
|
|
|
window.requestAnimationFrame(() => {
|
|
|
|
window.requestAnimationFrame(() => {
|
|
|
|
NylasEnv.getCurrentWindow().updateLoadSettings({
|
|
|
|
windowType: "composer",
|
|
|
|
})
|
2016-04-29 04:42:06 +08:00
|
|
|
})
|
2016-04-30 05:30:25 +08:00
|
|
|
})
|
2016-04-05 09:21:39 +08:00
|
|
|
});
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<ComposerViewForDraftClientId
|
|
|
|
ref="composer"
|
2016-04-30 05:30:25 +08:00
|
|
|
onDraftReady={this._onDraftReady}
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
draftClientId={this.state.draftClientId}
|
|
|
|
className="composer-full-window"
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_showInitialErrorDialog(msg) {
|
|
|
|
const dialog = remote.require('dialog');
|
|
|
|
// We delay so the view has time to update the restored draft. If we
|
|
|
|
// don't delay the modal may come up in a state where the draft looks
|
|
|
|
// like it hasn't been restored or has been lost.
|
|
|
|
_.delay(() => {
|
|
|
|
dialog.showMessageBox(remote.getCurrentWindow(), {
|
|
|
|
type: 'warning',
|
|
|
|
buttons: ['Okay'],
|
|
|
|
message: "Error",
|
|
|
|
detail: msg,
|
|
|
|
});
|
|
|
|
}, 100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function activate() {
|
|
|
|
// Register our composer as the window-wide Composer
|
|
|
|
ComponentRegistry.register(ComposerViewForDraftClientId, {
|
|
|
|
role: 'Composer',
|
|
|
|
});
|
|
|
|
|
|
|
|
if (NylasEnv.isMainWindow()) {
|
|
|
|
ComponentRegistry.register(ComposeButton, {
|
|
|
|
location: WorkspaceStore.Location.RootSidebar.Toolbar,
|
|
|
|
});
|
|
|
|
}
|
2016-04-23 04:30:42 +08:00
|
|
|
|
|
|
|
NylasEnv.getCurrentWindow().setMinimumSize(480, 250);
|
2016-04-23 08:39:29 +08:00
|
|
|
|
|
|
|
const silent = !NylasEnv.isMainWindow()
|
|
|
|
WorkspaceStore.defineSheet('Main', {root: true, silent}, {
|
2016-04-23 04:30:42 +08:00
|
|
|
popout: ['Center'],
|
|
|
|
});
|
|
|
|
ComponentRegistry.register(ComposerWithWindowProps, {
|
|
|
|
location: WorkspaceStore.Location.Center,
|
|
|
|
});
|
2016-04-23 08:39:29 +08:00
|
|
|
|
|
|
|
if (silent) {
|
|
|
|
Actions.selectRootSheet(WorkspaceStore.Sheet.Main)
|
|
|
|
}
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function deactivate() {
|
|
|
|
ComponentRegistry.unregister(ComposerViewForDraftClientId);
|
|
|
|
ComponentRegistry.unregister(ComposeButton);
|
|
|
|
ComponentRegistry.unregister(ComposerWithWindowProps);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function serialize() {
|
|
|
|
return this.state;
|
|
|
|
}
|