Merge pull request #2996 from matrix-org/bwindels/composerdesign

Message editing: apply design
This commit is contained in:
Bruno Windels 2019-05-20 08:42:41 +00:00 committed by GitHub
commit 1368a5eb80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 60 additions and 23 deletions

View file

@ -16,17 +16,22 @@ limitations under the License.
.mx_MessageEditor { .mx_MessageEditor {
border-radius: 4px; border-radius: 4px;
background-color: $header-panel-bg-color; padding: 3px;
padding: 11px 13px 7px 56px; // this is to try not make the text move but still have some
// padding around and in the editor.
// Actual values from fiddling around in inspector
margin: -7px -10px -5px -10px;
.mx_MessageEditor_editor { .mx_MessageEditor_editor {
border-radius: 4px; border-radius: 4px;
border: solid 1px #e9edf1; border: solid 1px $primary-hairline-color;
background-color: #ffffff; background-color: $primary-bg-color;
padding: 10px; padding: 3px 6px;
white-space: pre-wrap; white-space: pre-wrap;
word-wrap: break-word; word-wrap: break-word;
outline: none; outline: none;
max-height: 200px;
overflow-x: auto;
span { span {
display: inline-block; display: inline-block;
@ -48,8 +53,15 @@ limitations under the License.
.mx_MessageEditor_buttons { .mx_MessageEditor_buttons {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: end; justify-content: flex-end;
padding: 5px 0; padding: 5px;
position: absolute;
left: 0;
background: $header-panel-bg-color;
z-index: 100;
right: 0;
margin: 0 -110px 0 0;
padding-right: 104px;
.mx_AccessibleButton { .mx_AccessibleButton {
margin-left: 5px; margin-left: 5px;
@ -62,3 +74,8 @@ limitations under the License.
height: 0; height: 0;
} }
} }
.mx_EventTile_last .mx_MessageEditor_buttons {
position: static;
margin-right: -103px;
}

View file

@ -43,6 +43,10 @@ limitations under the License.
padding-top: 0px ! important; padding-top: 0px ! important;
} }
.mx_EventTile_isEditing {
background-color: $header-panel-bg-color;
}
.mx_EventTile .mx_SenderProfile { .mx_EventTile .mx_SenderProfile {
color: $primary-fg-color; color: $primary-fg-color;
font-size: 14px; font-size: 14px;
@ -72,6 +76,10 @@ limitations under the License.
} }
} }
.mx_EventTile_isEditing .mx_MessageTimestamp {
visibility: hidden !important;
}
.mx_EventTile .mx_MessageTimestamp { .mx_EventTile .mx_MessageTimestamp {
display: block; display: block;
visibility: hidden; visibility: hidden;

View file

@ -541,8 +541,8 @@ export function bodyToHtml(content, highlights, opts={}) {
}); });
return isDisplayedWithHtml ? return isDisplayedWithHtml ?
<span className={className} dangerouslySetInnerHTML={{ __html: safeBody }} dir="auto" /> : <span key="body" className={className} dangerouslySetInnerHTML={{ __html: safeBody }} dir="auto" /> :
<span className={className} dir="auto">{ strippedBody }</span>; <span key="body" className={className} dir="auto">{ strippedBody }</span>;
} }
export function emojifyText(text, addAlt) { export function emojifyText(text, addAlt) {

View file

@ -455,14 +455,10 @@ module.exports = React.createClass({
_getTilesForEvent: function(prevEvent, mxEv, last) { _getTilesForEvent: function(prevEvent, mxEv, last) {
const EventTile = sdk.getComponent('rooms.EventTile'); const EventTile = sdk.getComponent('rooms.EventTile');
const MessageEditor = sdk.getComponent('elements.MessageEditor');
const DateSeparator = sdk.getComponent('messages.DateSeparator'); const DateSeparator = sdk.getComponent('messages.DateSeparator');
const ret = []; const ret = [];
if (this.props.editEvent && this.props.editEvent.getId() === mxEv.getId()) { const isEditing = this.props.editEvent && this.props.editEvent.getId() === mxEv.getId();
return [<MessageEditor key={mxEv.getId()} event={mxEv} />];
}
// is this a continuation of the previous message? // is this a continuation of the previous message?
let continuation = false; let continuation = false;
@ -532,6 +528,7 @@ module.exports = React.createClass({
continuation={continuation} continuation={continuation}
isRedacted={mxEv.isRedacted()} isRedacted={mxEv.isRedacted()}
replacingEventId={mxEv.replacingEventId()} replacingEventId={mxEv.replacingEventId()}
isEditing={isEditing}
onHeightChanged={this._onHeightChanged} onHeightChanged={this._onHeightChanged}
readReceipts={readReceipts} readReceipts={readReceipts}
readReceiptMap={this._readReceiptMap} readReceiptMap={this._readReceiptMap}

View file

@ -107,10 +107,12 @@ export default class MessageEditor extends React.Component {
} else if (event.key === "Enter") { } else if (event.key === "Enter") {
this._sendEdit(); this._sendEdit();
event.preventDefault(); event.preventDefault();
} else if (event.key === "Escape") {
this._cancelEdit();
} }
} }
_onCancelClicked = () => { _cancelEdit = () => {
dis.dispatch({action: "edit_event", event: null}); dis.dispatch({action: "edit_event", event: null});
} }
@ -185,7 +187,7 @@ export default class MessageEditor extends React.Component {
ref={ref => this._editorRef = ref} ref={ref => this._editorRef = ref}
></div> ></div>
<div className="mx_MessageEditor_buttons"> <div className="mx_MessageEditor_buttons">
<AccessibleButton kind="secondary" onClick={this._onCancelClicked}>{_t("Cancel")}</AccessibleButton> <AccessibleButton kind="secondary" onClick={this._cancelEdit}>{_t("Cancel")}</AccessibleButton>
<AccessibleButton kind="primary" onClick={this._sendEdit}>{_t("Save")}</AccessibleButton> <AccessibleButton kind="primary" onClick={this._sendEdit}>{_t("Save")}</AccessibleButton>
</div> </div>
</div>; </div>;

View file

@ -90,6 +90,7 @@ module.exports = React.createClass({
tileShape={this.props.tileShape} tileShape={this.props.tileShape}
maxImageHeight={this.props.maxImageHeight} maxImageHeight={this.props.maxImageHeight}
replacingEventId={this.props.replacingEventId} replacingEventId={this.props.replacingEventId}
isEditing={this.props.isEditing}
onHeightChanged={this.props.onHeightChanged} />; onHeightChanged={this.props.onHeightChanged} />;
}, },
}); });

View file

@ -89,7 +89,9 @@ module.exports = React.createClass({
componentDidMount: function() { componentDidMount: function() {
this._unmounted = false; this._unmounted = false;
this._applyFormatting(); if (!this.props.isEditing) {
this._applyFormatting();
}
}, },
_applyFormatting() { _applyFormatting() {
@ -128,11 +130,14 @@ module.exports = React.createClass({
}, },
componentDidUpdate: function(prevProps) { componentDidUpdate: function(prevProps) {
const messageWasEdited = prevProps.replacingEventId !== this.props.replacingEventId; if (!this.props.isEditing) {
if (messageWasEdited) { const stoppedEditing = prevProps.isEditing && !this.props.isEditing;
this._applyFormatting(); const messageWasEdited = prevProps.replacingEventId !== this.props.replacingEventId;
if (messageWasEdited || stoppedEditing) {
this._applyFormatting();
}
this.calculateUrlPreview();
} }
this.calculateUrlPreview();
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
@ -148,6 +153,7 @@ module.exports = React.createClass({
nextProps.replacingEventId !== this.props.replacingEventId || nextProps.replacingEventId !== this.props.replacingEventId ||
nextProps.highlightLink !== this.props.highlightLink || nextProps.highlightLink !== this.props.highlightLink ||
nextProps.showUrlPreview !== this.props.showUrlPreview || nextProps.showUrlPreview !== this.props.showUrlPreview ||
nextProps.isEditing !== this.props.isEditing ||
nextState.links !== this.state.links || nextState.links !== this.state.links ||
nextState.editedMarkerHovered !== this.state.editedMarkerHovered || nextState.editedMarkerHovered !== this.state.editedMarkerHovered ||
nextState.widgetHidden !== this.state.widgetHidden); nextState.widgetHidden !== this.state.widgetHidden);
@ -463,6 +469,10 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
if (this.props.isEditing) {
const MessageEditor = sdk.getComponent('elements.MessageEditor');
return <MessageEditor event={this.props.mxEvent} />;
}
const EmojiText = sdk.getComponent('elements.EmojiText'); const EmojiText = sdk.getComponent('elements.EmojiText');
const mxEvent = this.props.mxEvent; const mxEvent = this.props.mxEvent;
const content = mxEvent.getContent(); const content = mxEvent.getContent();

View file

@ -543,6 +543,7 @@ module.exports = withMatrixClient(React.createClass({
const classes = classNames({ const classes = classNames({
mx_EventTile: true, mx_EventTile: true,
mx_EventTile_isEditing: this.props.isEditing,
mx_EventTile_info: isInfoMessage, mx_EventTile_info: isInfoMessage,
mx_EventTile_12hr: this.props.isTwelveHour, mx_EventTile_12hr: this.props.isTwelveHour,
mx_EventTile_encrypting: this.props.eventSendStatus === 'encrypting', mx_EventTile_encrypting: this.props.eventSendStatus === 'encrypting',
@ -620,14 +621,14 @@ module.exports = withMatrixClient(React.createClass({
} }
const MessageActionBar = sdk.getComponent('messages.MessageActionBar'); const MessageActionBar = sdk.getComponent('messages.MessageActionBar');
const actionBar = <MessageActionBar const actionBar = !this.props.isEditing ? <MessageActionBar
mxEvent={this.props.mxEvent} mxEvent={this.props.mxEvent}
reactions={this.state.reactions} reactions={this.state.reactions}
permalinkCreator={this.props.permalinkCreator} permalinkCreator={this.props.permalinkCreator}
getTile={this.getTile} getTile={this.getTile}
getReplyThread={this.getReplyThread} getReplyThread={this.getReplyThread}
onFocusChange={this.onActionBarFocusChange} onFocusChange={this.onActionBarFocusChange}
/>; /> : undefined;
const timestamp = this.props.mxEvent.getTs() ? const timestamp = this.props.mxEvent.getTs() ?
<MessageTimestamp showTwelveHour={this.props.isTwelveHour} ts={this.props.mxEvent.getTs()} /> : null; <MessageTimestamp showTwelveHour={this.props.isTwelveHour} ts={this.props.mxEvent.getTs()} /> : null;
@ -783,6 +784,7 @@ module.exports = withMatrixClient(React.createClass({
<EventTileType ref="tile" <EventTileType ref="tile"
mxEvent={this.props.mxEvent} mxEvent={this.props.mxEvent}
replacingEventId={this.props.replacingEventId} replacingEventId={this.props.replacingEventId}
isEditing={this.props.isEditing}
highlights={this.props.highlights} highlights={this.props.highlights}
highlightLink={this.props.highlightLink} highlightLink={this.props.highlightLink}
showUrlPreview={this.props.showUrlPreview} showUrlPreview={this.props.showUrlPreview}