Merge pull request #6619 from matrix-org/gsouquet/ts-components-migration

This commit is contained in:
Germain 2021-09-03 08:47:12 +01:00 committed by GitHub
commit e16921e1f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 347 additions and 346 deletions

View file

@ -243,6 +243,7 @@ interface IProps {
// opaque readreceipt info for each userId; used by ReadReceiptMarker
// to manage its animations. Should be an empty object when the room
// first loads
// TODO: Proper typing for RR info
readReceiptMap?: any;
// A function which is used to check if the parent panel is being

View file

@ -14,11 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton';
import classNames from 'classnames';
export default (props) => {
interface IProps {
numUnreadMessages: number;
highlight: boolean;
onScrollToBottomClick: (e: React.MouseEvent) => void;
}
const JumpToBottomButton: React.FC<IProps> = (props) => {
const className = classNames({
'mx_JumpToBottomButton': true,
'mx_JumpToBottomButton_highlight': props.highlight,
@ -36,3 +43,5 @@ export default (props) => {
{ badge }
</div>);
};
export default JumpToBottomButton;

View file

@ -15,62 +15,75 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { createRef } from 'react';
import PropTypes from 'prop-types';
import React, { createRef, RefObject } from 'react';
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { _t } from '../../../languageHandler';
import { formatDate } from '../../../DateUtils';
import NodeAnimator from "../../../NodeAnimator";
import * as sdk from "../../../index";
import { toPx } from "../../../utils/units";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import MemberAvatar from '../avatars/MemberAvatar';
interface IProps {
// the RoomMember to show the RR for
member?: RoomMember;
// userId to fallback the avatar to
// if the member hasn't been loaded yet
fallbackUserId: string;
// number of pixels to offset the avatar from the right of its parent;
// typically a negative value.
leftOffset?: number;
// true to hide the avatar (it will still be animated)
hidden?: boolean;
// don't animate this RR into position
suppressAnimation?: boolean;
// an opaque object for storing information about this user's RR in
// this room
// TODO: proper typing for RR info
readReceiptInfo: any;
// A function which is used to check if the parent panel is being
// unmounted, to avoid unnecessary work. Should return true if we
// are being unmounted.
checkUnmounting?: () => boolean;
// callback for clicks on this RR
onClick?: (e: React.MouseEvent) => void;
// Timestamp when the receipt was read
timestamp?: number;
// True to show twelve hour format, false otherwise
showTwelveHour?: boolean;
}
interface IState {
suppressDisplay: boolean;
startStyles?: IReadReceiptMarkerStyle[];
}
interface IReadReceiptMarkerStyle {
top: number;
left: number;
}
@replaceableComponent("views.rooms.ReadReceiptMarker")
export default class ReadReceiptMarker extends React.PureComponent {
static propTypes = {
// the RoomMember to show the RR for
member: PropTypes.object,
// userId to fallback the avatar to
// if the member hasn't been loaded yet
fallbackUserId: PropTypes.string.isRequired,
// number of pixels to offset the avatar from the right of its parent;
// typically a negative value.
leftOffset: PropTypes.number,
// true to hide the avatar (it will still be animated)
hidden: PropTypes.bool,
// don't animate this RR into position
suppressAnimation: PropTypes.bool,
// an opaque object for storing information about this user's RR in
// this room
readReceiptInfo: PropTypes.object,
// A function which is used to check if the parent panel is being
// unmounted, to avoid unnecessary work. Should return true if we
// are being unmounted.
checkUnmounting: PropTypes.func,
// callback for clicks on this RR
onClick: PropTypes.func,
// Timestamp when the receipt was read
timestamp: PropTypes.number,
// True to show twelve hour format, false otherwise
showTwelveHour: PropTypes.bool,
};
export default class ReadReceiptMarker extends React.PureComponent<IProps, IState> {
private avatar: React.RefObject<HTMLDivElement | HTMLImageElement | HTMLSpanElement> = createRef();
static defaultProps = {
leftOffset: 0,
};
constructor(props) {
constructor(props: IProps) {
super(props);
this._avatar = createRef();
this.state = {
// if we are going to animate the RR, we don't show it on first render,
// and instead just add a placeholder to the DOM; once we've been
@ -80,7 +93,7 @@ export default class ReadReceiptMarker extends React.PureComponent {
};
}
componentWillUnmount() {
public componentWillUnmount(): void {
// before we remove the rr, store its location in the map, so that if
// it reappears, it can be animated from the right place.
const rrInfo = this.props.readReceiptInfo;
@ -95,29 +108,29 @@ export default class ReadReceiptMarker extends React.PureComponent {
return;
}
const avatarNode = this._avatar.current;
const avatarNode = this.avatar.current;
rrInfo.top = avatarNode.offsetTop;
rrInfo.left = avatarNode.offsetLeft;
rrInfo.parent = avatarNode.offsetParent;
}
componentDidMount() {
public componentDidMount(): void {
if (!this.state.suppressDisplay) {
// we've already done our display - nothing more to do.
return;
}
this._animateMarker();
this.animateMarker();
}
componentDidUpdate(prevProps) {
public componentDidUpdate(prevProps: IProps): void {
const differentLeftOffset = prevProps.leftOffset !== this.props.leftOffset;
const visibilityChanged = prevProps.hidden !== this.props.hidden;
if (differentLeftOffset || visibilityChanged) {
this._animateMarker();
this.animateMarker();
}
}
_animateMarker() {
private animateMarker(): void {
// treat new RRs as though they were off the top of the screen
let oldTop = -15;
@ -126,7 +139,7 @@ export default class ReadReceiptMarker extends React.PureComponent {
oldTop = oldInfo.top + oldInfo.parent.getBoundingClientRect().top;
}
const newElement = this._avatar.current;
const newElement = this.avatar.current;
let startTopOffset;
if (!newElement.offsetParent) {
// this seems to happen sometimes for reasons I don't understand
@ -156,10 +169,9 @@ export default class ReadReceiptMarker extends React.PureComponent {
});
}
render() {
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
public render(): JSX.Element {
if (this.state.suppressDisplay) {
return <div ref={this._avatar} />;
return <div ref={this.avatar as RefObject<HTMLDivElement>} />;
}
const style = {
@ -198,7 +210,7 @@ export default class ReadReceiptMarker extends React.PureComponent {
style={style}
title={title}
onClick={this.props.onClick}
inputRef={this._avatar}
inputRef={this.avatar as RefObject<HTMLImageElement>}
/>
</NodeAnimator>
);

View file

@ -14,41 +14,38 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import React from 'react';
import { _t } from '../../../languageHandler';
import PropTypes from 'prop-types';
import { Room } from 'matrix-js-sdk/src';
import classNames from 'classnames';
import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import { roomShape } from './RoomDetailRow';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import RoomDetailRow from "./RoomDetailRow";
interface IProps {
rooms?: Room[];
className?: string;
}
@replaceableComponent("views.rooms.RoomDetailList")
export default class RoomDetailList extends React.Component {
static propTypes = {
rooms: PropTypes.arrayOf(roomShape),
className: PropTypes.string,
};
getRows() {
export default class RoomDetailList extends React.Component<IProps> {
private getRows(): JSX.Element[] {
if (!this.props.rooms) return [];
const RoomDetailRow = sdk.getComponent('rooms.RoomDetailRow');
return this.props.rooms.map((room, index) => {
return <RoomDetailRow key={index} room={room} onClick={this.onDetailsClick} />;
});
}
onDetailsClick = (ev, room) => {
private onDetailsClick = (ev: React.MouseEvent, room: Room): void => {
dis.dispatch({
action: 'view_room',
room_id: room.roomId,
room_alias: room.canonicalAlias || (room.aliases || [])[0],
room_alias: room.getCanonicalAlias() || (room.getAltAliases() || [])[0],
});
};
render() {
public render(): JSX.Element {
const rows = this.getRows();
let rooms;
if (rows.length === 0) {

View file

@ -195,7 +195,7 @@ export default class RoomHeader extends React.Component<IProps> {
videoCallButton =
<AccessibleTooltipButton
className="mx_RoomHeader_button mx_RoomHeader_videoCallButton"
onClick={(ev) => ev.shiftKey ?
onClick={(ev: React.MouseEvent<Element>) => ev.shiftKey ?
this.displayInfoDialogAboutScreensharing() : this.props.onCallPlaced(PlaceCallType.Video)}
title={_t("Video call")} />;
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2018-2020 New Vector Ltd
Copyright 2018-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,41 +15,43 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
import { Room } from 'matrix-js-sdk/src/models/room';
import { RoomState } from 'matrix-js-sdk/src/models/room-state';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import RoomUpgradeDialog from '../dialogs/RoomUpgradeDialog';
import AccessibleButton from '../elements/AccessibleButton';
interface IProps {
room: Room;
}
interface IState {
upgraded?: boolean;
}
@replaceableComponent("views.rooms.RoomUpgradeWarningBar")
export default class RoomUpgradeWarningBar extends React.PureComponent {
static propTypes = {
room: PropTypes.object.isRequired,
recommendation: PropTypes.object.isRequired,
};
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, IState> {
public componentDidMount(): void {
const tombstone = this.props.room.currentState.getStateEvents("m.room.tombstone", "");
this.setState({ upgraded: tombstone && tombstone.getContent().replacement_room });
MatrixClientPeg.get().on("RoomState.events", this._onStateEvents);
MatrixClientPeg.get().on("RoomState.events", this.onStateEvents);
}
componentWillUnmount() {
public componentWillUnmount(): void {
const cli = MatrixClientPeg.get();
if (cli) {
cli.removeListener("RoomState.events", this._onStateEvents);
cli.removeListener("RoomState.events", this.onStateEvents);
}
}
_onStateEvents = (event, state) => {
private onStateEvents = (event: MatrixEvent, state: RoomState): void => {
if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
return;
}
@ -60,14 +62,11 @@ export default class RoomUpgradeWarningBar extends React.PureComponent {
this.setState({ upgraded: tombstone && tombstone.getContent().replacement_room });
};
onUpgradeClick = () => {
const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
private onUpgradeClick = (): void => {
Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, { room: this.props.room });
};
render() {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
public render(): JSX.Element {
let doUpgradeWarnings = (
<div>
<div className="mx_RoomUpgradeWarningBar_body">

View file

@ -1,5 +1,5 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2016-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,23 +15,21 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
title?: string;
// `src` to an image. Optional.
icon?: string;
}
/*
* A stripped-down room header used for things like the user settings
* and room directory.
*/
@replaceableComponent("views.rooms.SimpleRoomHeader")
export default class SimpleRoomHeader extends React.Component {
static propTypes = {
title: PropTypes.string,
// `src` to an image. Optional.
icon: PropTypes.string,
};
render() {
export default class SimpleRoomHeader extends React.PureComponent<IProps> {
public render(): JSX.Element {
let icon;
if (this.props.icon) {
icon = <img

View file

@ -1,7 +1,5 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2019 New Vector Ltd
Copyright 2016 - 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -17,19 +15,18 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton';
import { replaceableComponent } from "../../../utils/replaceableComponent";
@replaceableComponent("views.rooms.TopUnreadMessagesBar")
export default class TopUnreadMessagesBar extends React.Component {
static propTypes = {
onScrollUpClick: PropTypes.func,
onCloseClick: PropTypes.func,
};
interface IProps {
onScrollUpClick?: (e: React.MouseEvent) => void;
onCloseClick?: (e: React.MouseEvent) => void;
}
render() {
@replaceableComponent("views.rooms.TopUnreadMessagesBar")
export default class TopUnreadMessagesBar extends React.PureComponent<IProps> {
public render(): JSX.Element {
return (
<div className="mx_TopUnreadMessagesBar">
<AccessibleButton