Tweak default right panel size to be 320px except for maximised widgets at 420px (#110)

* Add extra buttons to room summary card

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove right panel tabs in favour of X button on each panel

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update room summary card header to align close button correctly

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix typo in pinned messages heading

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update tests

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update screenshot

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Improve coverage

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Tweak default right panel size to be 320px except for video rooms/maximised widgets at 420px

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update tests

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Track panel resizing in analytics

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix import cycle

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update screenshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Improve coverage

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix tests

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshot

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update test/components/structures/MainSplit-test.tsx

Co-authored-by: David Baker <dbkr@users.noreply.github.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
This commit is contained in:
Michael Telatynski 2024-10-04 10:41:00 +01:00 committed by GitHub
parent 70418f8f3d
commit 0a9b4aecd3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 435 additions and 56 deletions

View file

@ -72,7 +72,7 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@matrix-org/analytics-events": "^0.25.0", "@matrix-org/analytics-events": "^0.26.0",
"@matrix-org/emojibase-bindings": "^1.1.2", "@matrix-org/emojibase-bindings": "^1.1.2",
"@matrix-org/matrix-wysiwyg": "2.37.9", "@matrix-org/matrix-wysiwyg": "2.37.9",
"@matrix-org/react-sdk-module-api": "^2.4.0", "@matrix-org/react-sdk-module-api": "^2.4.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -10,8 +10,10 @@ Please see LICENSE files in the repository root for full details.
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import { NumberSize, Resizable } from "re-resizable"; import { NumberSize, Resizable } from "re-resizable";
import { Direction } from "re-resizable/lib/resizer"; import { Direction } from "re-resizable/lib/resizer";
import { WebPanelResize } from "@matrix-org/analytics-events/types/typescript/WebPanelResize";
import ResizeNotifier from "../../utils/ResizeNotifier"; import ResizeNotifier from "../../utils/ResizeNotifier";
import { PosthogAnalytics } from "../../PosthogAnalytics.ts";
interface IProps { interface IProps {
resizeNotifier: ResizeNotifier; resizeNotifier: ResizeNotifier;
@ -26,14 +28,16 @@ interface IProps {
*/ */
sizeKey?: string; sizeKey?: string;
/** /**
* The size to use for the panel component if one isn't persisted in storage. Defaults to 350. * The size to use for the panel component if one isn't persisted in storage. Defaults to 320.
*/ */
defaultSize: number; defaultSize: number;
analyticsRoomType: WebPanelResize["roomType"];
} }
export default class MainSplit extends React.Component<IProps> { export default class MainSplit extends React.Component<IProps> {
public static defaultProps = { public static defaultProps = {
defaultSize: 350, defaultSize: 320,
}; };
private onResizeStart = (): void => { private onResizeStart = (): void => {
@ -58,11 +62,16 @@ export default class MainSplit extends React.Component<IProps> {
elementRef: HTMLElement, elementRef: HTMLElement,
delta: NumberSize, delta: NumberSize,
): void => { ): void => {
const newSize = this.loadSidePanelSize().width + delta.width;
this.props.resizeNotifier.stopResizing(); this.props.resizeNotifier.stopResizing();
window.localStorage.setItem( window.localStorage.setItem(this.sizeSettingStorageKey, newSize.toString());
this.sizeSettingStorageKey,
(this.loadSidePanelSize().width + delta.width).toString(), PosthogAnalytics.instance.trackEvent<WebPanelResize>({
); eventName: "WebPanelResize",
panel: "right",
roomType: this.props.analyticsRoomType,
size: newSize,
});
}; };
private loadSidePanelSize(): { height: string | number; width: number } { private loadSidePanelSize(): { height: string | number; width: number } {

View file

@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details. Please see LICENSE files in the repository root for full details.
*/ */
import React, { ChangeEvent, createRef, ReactElement, ReactNode, RefObject, useContext } from "react"; import React, { ChangeEvent, ComponentProps, createRef, ReactElement, ReactNode, RefObject, useContext } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { import {
IRecommendedVersion, IRecommendedVersion,
@ -54,7 +54,7 @@ import WidgetEchoStore from "../../stores/WidgetEchoStore";
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import { Layout } from "../../settings/enums/Layout"; import { Layout } from "../../settings/enums/Layout";
import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton"; import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton";
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext"; import RoomContext, { TimelineRenderingType, MainSplitContentType } from "../../contexts/RoomContext";
import { E2EStatus, shieldStatusForRoom } from "../../utils/ShieldUtils"; import { E2EStatus, shieldStatusForRoom } from "../../utils/ShieldUtils";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import { IMatrixClientCreds } from "../../MatrixClientPeg"; import { IMatrixClientCreds } from "../../MatrixClientPeg";
@ -152,13 +152,8 @@ interface IRoomProps {
onRegistered?(credentials: IMatrixClientCreds): void; onRegistered?(credentials: IMatrixClientCreds): void;
} }
// This defines the content of the mainSplit. export { MainSplitContentType };
// If the mainSplit does not contain the Timeline, the chat is shown in the right panel.
export enum MainSplitContentType {
Timeline,
MaximisedWidget,
Call,
}
export interface IRoomState { export interface IRoomState {
room?: Room; room?: Room;
virtualRoom?: Room; virtualRoom?: Room;
@ -191,11 +186,6 @@ export interface IRoomState {
showApps: boolean; showApps: boolean;
isPeeking: boolean; isPeeking: boolean;
showRightPanel: boolean; showRightPanel: boolean;
/**
* Whether the right panel shown is either of ThreadPanel or ThreadView.
* Always false when `showRightPanel` is false.
*/
threadRightPanel: boolean;
// error object, as from the matrix client/server API // error object, as from the matrix client/server API
// If we failed to load information about the room, // If we failed to load information about the room,
// store the error here. // store the error here.
@ -234,7 +224,7 @@ export interface IRoomState {
e2eStatus?: E2EStatus; e2eStatus?: E2EStatus;
rejecting?: boolean; rejecting?: boolean;
hasPinnedWidgets?: boolean; hasPinnedWidgets?: boolean;
mainSplitContentType?: MainSplitContentType; mainSplitContentType: MainSplitContentType;
// whether or not a spaces context switch brought us here, // whether or not a spaces context switch brought us here,
// if it did we don't want the room to be marked as read as soon as it is loaded. // if it did we don't want the room to be marked as read as soon as it is loaded.
wasContextSwitch?: boolean; wasContextSwitch?: boolean;
@ -399,7 +389,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
showApps: false, showApps: false,
isPeeking: false, isPeeking: false,
showRightPanel: false, showRightPanel: false,
threadRightPanel: false,
joining: false, joining: false,
showTopUnreadMessagesBar: false, showTopUnreadMessagesBar: false,
statusBarVisible: false, statusBarVisible: false,
@ -626,11 +615,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
mainSplitContentType: room ? this.getMainSplitContentType(room) : undefined, mainSplitContentType: room ? this.getMainSplitContentType(room) : undefined,
initialEventId: undefined, // default to clearing this, will get set later in the method if needed initialEventId: undefined, // default to clearing this, will get set later in the method if needed
showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false, showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false,
threadRightPanel: roomId
? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes(
this.context.rightPanelStore.currentCardForRoom(roomId).phase!,
)
: false,
activeCall: roomId ? CallStore.instance.getActiveCall(roomId) : null, activeCall: roomId ? CallStore.instance.getActiveCall(roomId) : null,
promptAskToJoin: this.context.roomViewStore.promptAskToJoin(), promptAskToJoin: this.context.roomViewStore.promptAskToJoin(),
viewRoomOpts: this.context.roomViewStore.getViewRoomOpts(), viewRoomOpts: this.context.roomViewStore.getViewRoomOpts(),
@ -1033,11 +1017,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
const { roomId } = this.state; const { roomId } = this.state;
this.setState({ this.setState({
showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false, showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false,
threadRightPanel: roomId
? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes(
this.context.rightPanelStore.currentCardForRoom(roomId).phase!,
)
: false,
}); });
}; };
@ -2531,6 +2510,17 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
const mainSplitContentClasses = classNames("mx_RoomView_body", mainSplitContentClassName); const mainSplitContentClasses = classNames("mx_RoomView_body", mainSplitContentClassName);
let sizeKey: string | undefined;
let defaultSize: number | undefined;
let analyticsRoomType: ComponentProps<typeof MainSplit>["analyticsRoomType"] = "other_room";
if (this.state.mainSplitContentType !== MainSplitContentType.Timeline) {
// Override defaults for video rooms where more space is needed for the chat timeline
sizeKey = "wide";
defaultSize = 420;
analyticsRoomType =
this.state.mainSplitContentType === MainSplitContentType.Call ? "video_room" : "maximised_widget";
}
return ( return (
<RoomContext.Provider value={this.state}> <RoomContext.Provider value={this.state}>
<div className={mainClasses} ref={this.roomView} onKeyDown={this.onReactKeyDown}> <div className={mainClasses} ref={this.roomView} onKeyDown={this.onReactKeyDown}>
@ -2541,10 +2531,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
<MainSplit <MainSplit
panel={rightPanel} panel={rightPanel}
resizeNotifier={this.props.resizeNotifier} resizeNotifier={this.props.resizeNotifier}
// Override defaults when a thread is being shown to allow persisting a separate sizeKey={sizeKey}
// right panel width for thread panels as they tend to want to be wider. defaultSize={defaultSize}
sizeKey={this.state.threadRightPanel ? "thread" : undefined} analyticsRoomType={analyticsRoomType}
defaultSize={this.state.threadRightPanel ? 500 : undefined}
> >
<div <div
className={mainSplitContentClasses} className={mainSplitContentClasses}

View file

@ -764,7 +764,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
return ( return (
<main className="mx_SpaceRoomView"> <main className="mx_SpaceRoomView">
<ErrorBoundary> <ErrorBoundary>
<MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier}> <MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier} analyticsRoomType="space">
{this.renderBody()} {this.renderBody()}
</MainSplit> </MainSplit>
</ErrorBoundary> </ErrorBoundary>

View file

@ -87,7 +87,12 @@ export default class UserView extends React.Component<IProps, IState> {
/> />
); );
return ( return (
<MainSplit panel={panel} resizeNotifier={this.props.resizeNotifier}> <MainSplit
panel={panel}
resizeNotifier={this.props.resizeNotifier}
defaultSize={420}
analyticsRoomType="user_profile"
>
<UserOnboardingPage /> <UserOnboardingPage />
</MainSplit> </MainSplit>
); );

View file

@ -21,6 +21,14 @@ export enum TimelineRenderingType {
Pinned = "Pinned", Pinned = "Pinned",
} }
// This defines the content of the mainSplit.
// If the mainSplit does not contain the Timeline, the chat is shown in the right panel.
export enum MainSplitContentType {
Timeline,
MaximisedWidget,
Call,
}
const RoomContext = createContext< const RoomContext = createContext<
IRoomState & { IRoomState & {
threadId?: string; threadId?: string;
@ -35,7 +43,6 @@ const RoomContext = createContext<
showApps: false, showApps: false,
isPeeking: false, isPeeking: false,
showRightPanel: true, showRightPanel: true,
threadRightPanel: false,
joining: false, joining: false,
showTopUnreadMessagesBar: false, showTopUnreadMessagesBar: false,
statusBarVisible: false, statusBarVisible: false,
@ -59,6 +66,7 @@ const RoomContext = createContext<
matrixClientIsReady: false, matrixClientIsReady: false,
showUrlPreview: false, showUrlPreview: false,
timelineRenderingType: TimelineRenderingType.Room, timelineRenderingType: TimelineRenderingType.Room,
mainSplitContentType: MainSplitContentType.Timeline,
threadId: undefined, threadId: undefined,
liveTimeline: undefined, liveTimeline: undefined,
narrow: false, narrow: false,

View file

@ -7,10 +7,11 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React from "react"; import React from "react";
import { render } from "@testing-library/react"; import { fireEvent, render } from "@testing-library/react";
import MainSplit from "../../../src/components/structures/MainSplit"; import MainSplit from "../../../src/components/structures/MainSplit";
import ResizeNotifier from "../../../src/utils/ResizeNotifier"; import ResizeNotifier from "../../../src/utils/ResizeNotifier";
import { PosthogAnalytics } from "../../../src/PosthogAnalytics.ts";
describe("<MainSplit/>", () => { describe("<MainSplit/>", () => {
const resizeNotifier = new ResizeNotifier(); const resizeNotifier = new ResizeNotifier();
@ -21,18 +22,33 @@ describe("<MainSplit/>", () => {
); );
const panel = <div>Right panel</div>; const panel = <div>Right panel</div>;
beforeEach(() => {
localStorage.clear();
});
it("renders", () => { it("renders", () => {
const { asFragment, container } = render( const { asFragment, container } = render(
<MainSplit resizeNotifier={resizeNotifier} children={children} panel={panel} />, <MainSplit
resizeNotifier={resizeNotifier}
children={children}
panel={panel}
analyticsRoomType="other_room"
/>,
); );
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
// Assert it matches the default width of 350 // Assert it matches the default width of 320
expect(container.querySelector<HTMLElement>(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("350px"); expect(container.querySelector<HTMLElement>(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("320px");
}); });
it("respects defaultSize prop", () => { it("respects defaultSize prop", () => {
const { asFragment, container } = render( const { asFragment, container } = render(
<MainSplit resizeNotifier={resizeNotifier} children={children} panel={panel} defaultSize={500} />, <MainSplit
resizeNotifier={resizeNotifier}
children={children}
panel={panel}
defaultSize={500}
analyticsRoomType="other_room"
/>,
); );
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
// Assert it matches the default width of 350 // Assert it matches the default width of 350
@ -48,8 +64,36 @@ describe("<MainSplit/>", () => {
panel={panel} panel={panel}
sizeKey="thread" sizeKey="thread"
defaultSize={400} defaultSize={400}
analyticsRoomType="other_room"
/>, />,
); );
expect(container.querySelector<HTMLElement>(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("333px"); expect(container.querySelector<HTMLElement>(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("333px");
}); });
it("should report to analytics on resize stop", () => {
const { container } = render(
<MainSplit
resizeNotifier={resizeNotifier}
children={children}
panel={panel}
sizeKey="thread"
defaultSize={400}
analyticsRoomType="other_room"
/>,
);
const spy = jest.spyOn(PosthogAnalytics.instance, "trackEvent");
const handle = container.querySelector(".mx_ResizeHandle--horizontal")!;
fireEvent.mouseDown(handle);
fireEvent.mouseMove(handle, { clientX: 0 });
fireEvent.mouseUp(handle);
expect(spy).toHaveBeenCalledWith({
eventName: "WebPanelResize",
panel: "right",
roomType: "other_room",
size: 400,
});
});
}); });

View file

@ -311,6 +311,12 @@ describe("RoomView", () => {
expect(stores.rightPanelStore.isOpen).toEqual(true); expect(stores.rightPanelStore.isOpen).toEqual(true);
expect(stores.rightPanelStore.currentCard.phase).toEqual(RightPanelPhases.Timeline); expect(stores.rightPanelStore.currentCard.phase).toEqual(RightPanelPhases.Timeline);
}); });
it("should render joined video room view", async () => {
jest.spyOn(room, "getMyMembership").mockReturnValue(KnownMembership.Join);
const { asFragment } = await mountRoomView();
expect(asFragment()).toMatchSnapshot();
});
}); });
describe("for a local room", () => { describe("for a local room", () => {

View file

@ -14,7 +14,7 @@ exports[`<MainSplit/> renders 1`] = `
</div> </div>
<div <div
class="mx_RightPanel_ResizeWrapper" class="mx_RightPanel_ResizeWrapper"
style="position: relative; user-select: auto; width: 350px; height: 100%; max-width: 50%; min-width: 264px; box-sizing: border-box; flex-shrink: 0;" style="position: relative; user-select: auto; width: 320px; height: 100%; max-width: 50%; min-width: 264px; box-sizing: border-box; flex-shrink: 0;"
> >
<div> <div>
Right panel Right panel

View file

@ -1125,3 +1125,322 @@ exports[`RoomView should show error view if failed to look up room alias 1`] = `
</div> </div>
</DocumentFragment> </DocumentFragment>
`; `;
exports[`RoomView video rooms should render joined video room view 1`] = `
<DocumentFragment>
<div
class="mx_RoomView mx_RoomView_immersive"
>
<canvas
aria-hidden="true"
height="768"
style="display: block; z-index: 999999; pointer-events: none; position: fixed; top: 0px; right: 0px;"
width="0"
/>
<div
class="mx_MainSplit"
>
<div
class="mx_RoomView_body mx_MainSplit_call"
data-layout="group"
>
<header
class="mx_Flex mx_RoomHeader light-panel"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x);"
>
<button
aria-label="Open room settings"
aria-live="off"
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="button"
style="--cpd-avatar-size: 40px;"
tabindex="-1"
>
!
</button>
<button
aria-label="Room info"
class="mx_RoomHeader_infoWrapper"
tabindex="0"
>
<div
class="mx_Box mx_RoomHeader_info mx_Box--flex"
style="--mx-box-flex: 1;"
>
<div
aria-level="1"
class="_typography_yh5dq_162 _font-body-lg-semibold_yh5dq_83 mx_RoomHeader_heading"
dir="auto"
role="heading"
>
<span
class="mx_RoomHeader_truncated mx_lineClamp"
>
!10:example.org
</span>
</div>
</div>
</button>
<div
class="mx_Flex"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
>
<button
aria-label="Room info"
class="_icon-button_bh2qc_17"
role="button"
style="--cpd-icon-button-size: 32px;"
tabindex="0"
>
<div
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<div />
</div>
</button>
<button
aria-label="Chat"
class="_icon-button_bh2qc_17"
role="button"
style="--cpd-icon-button-size: 32px;"
tabindex="0"
>
<div
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<div />
</div>
</button>
<button
aria-label="Threads"
class="_icon-button_bh2qc_17"
role="button"
style="--cpd-icon-button-size: 32px;"
tabindex="0"
>
<div
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<div />
</div>
</button>
</div>
<div
class="_typography_yh5dq_162 _font-body-sm-medium_yh5dq_50"
>
<div
aria-label="0 members"
class="mx_AccessibleButton mx_FacePile"
role="button"
tabindex="0"
>
<div
class="_stacked-avatars_mcap2_111"
/>
0
</div>
</div>
</header>
</div>
<div
class="mx_RightPanel_ResizeWrapper"
style="position: relative; user-select: auto; width: 420px; height: 100%; max-width: 50%; min-width: 264px; box-sizing: border-box; flex-shrink: 0;"
>
<aside
class="mx_RightPanel"
id="mx_RightPanel"
>
<div
class="mx_BaseCard mx_ThreadPanel mx_TimelineCard"
>
<div
class="mx_BaseCard_header"
>
<div
class="mx_BaseCard_header_title"
>
<p
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 mx_BaseCard_header_title_heading"
role="heading"
>
Chat
</p>
</div>
<button
class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
data-testid="base-card-close-button"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
>
<div
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
/>
</svg>
</div>
</button>
</div>
<div
class="mx_TimelineCard_timeline"
>
<div
class="mx_AutoHideScrollbar mx_ScrollPanel mx_RoomView_messagePanel"
tabindex="-1"
>
<div
class="mx_RoomView_messageListWrapper"
>
<ol
aria-live="polite"
class="mx_RoomView_MessageList"
style="height: 400px;"
/>
</div>
</div>
</div>
<div
aria-label="Message composer"
class="mx_MessageComposer mx_MessageComposer--compact"
role="region"
>
<div
class="mx_MessageComposer_wrapper"
>
<div
class="mx_MessageComposer_row"
>
<div
class="mx_SendMessageComposer"
>
<div
class="mx_BasicMessageComposer"
>
<div
aria-label="Formatting"
class="mx_MessageComposerFormatBar"
role="toolbar"
>
<button
aria-label="Bold"
class="mx_AccessibleButton mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIconBold"
role="button"
tabindex="0"
type="button"
/>
<button
aria-label="Italics"
class="mx_AccessibleButton mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIconItalic"
role="button"
tabindex="-1"
type="button"
/>
<button
aria-label="Strikethrough"
class="mx_AccessibleButton mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIconStrikethrough"
role="button"
tabindex="-1"
type="button"
/>
<button
aria-label="Code block"
class="mx_AccessibleButton mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIconCode"
role="button"
tabindex="-1"
type="button"
/>
<button
aria-label="Quote"
class="mx_AccessibleButton mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIconQuote"
role="button"
tabindex="-1"
type="button"
/>
<button
aria-label="Insert link"
class="mx_AccessibleButton mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIconInsertLink"
role="button"
tabindex="-1"
type="button"
/>
</div>
<div
aria-autocomplete="list"
aria-disabled="false"
aria-haspopup="listbox"
aria-label="Send a message…"
aria-multiline="true"
class="mx_BasicMessageComposer_input mx_BasicMessageComposer_input_shouldShowPillAvatar mx_BasicMessageComposer_inputEmpty"
contenteditable="true"
data-testid="basicmessagecomposer"
dir="auto"
role="textbox"
style="--placeholder: 'Send\\ a\\ message…';"
tabindex="0"
translate="no"
>
<div>
<br />
</div>
</div>
</div>
</div>
<div
class="mx_MessageComposer_actions"
>
<div
aria-label="Emoji"
class="mx_AccessibleButton mx_EmojiButton mx_MessageComposer_button mx_EmojiButton_icon"
role="button"
tabindex="0"
/>
<div
aria-label="Attachment"
class="mx_AccessibleButton mx_MessageComposer_button mx_MessageComposer_upload"
role="button"
tabindex="0"
/>
<div
aria-label="More options"
class="mx_AccessibleButton mx_MessageComposer_button mx_MessageComposer_buttonMenu"
role="button"
tabindex="0"
/>
<input
multiple=""
style="display: none;"
type="file"
/>
</div>
</div>
</div>
</div>
</div>
</aside>
<div>
<div
class="mx_ResizeHandle--horizontal"
style="position: absolute; user-select: none; width: 10px; height: 100%; top: 0px; left: -5px; cursor: col-resize;"
/>
</div>
</div>
</div>
</div>
</DocumentFragment>
`;

View file

@ -26,7 +26,7 @@ import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import defaultDispatcher from "../../../../src/dispatcher/dispatcher"; import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
import DocumentOffset from "../../../../src/editor/offset"; import DocumentOffset from "../../../../src/editor/offset";
import { Layout } from "../../../../src/settings/enums/Layout"; import { Layout } from "../../../../src/settings/enums/Layout";
import { IRoomState } from "../../../../src/components/structures/RoomView"; import { IRoomState, MainSplitContentType } from "../../../../src/components/structures/RoomView";
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks"; import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
import { mockPlatformPeg } from "../../../test-utils/platform"; import { mockPlatformPeg } from "../../../test-utils/platform";
import { doMaybeLocalRoomAction } from "../../../../src/utils/local-room"; import { doMaybeLocalRoomAction } from "../../../../src/utils/local-room";
@ -47,7 +47,6 @@ describe("<SendMessageComposer/>", () => {
showApps: false, showApps: false,
isPeeking: false, isPeeking: false,
showRightPanel: true, showRightPanel: true,
threadRightPanel: false,
joining: false, joining: false,
atEndOfLiveTimeline: true, atEndOfLiveTimeline: true,
showTopUnreadMessagesBar: false, showTopUnreadMessagesBar: false,
@ -69,6 +68,7 @@ describe("<SendMessageComposer/>", () => {
showDisplaynameChanges: true, showDisplaynameChanges: true,
matrixClientIsReady: false, matrixClientIsReady: false,
timelineRenderingType: TimelineRenderingType.Room, timelineRenderingType: TimelineRenderingType.Room,
mainSplitContentType: MainSplitContentType.Timeline,
liveTimeline: undefined, liveTimeline: undefined,
canSelfRedact: false, canSelfRedact: false,
resizing: false, resizing: false,

View file

@ -7,10 +7,10 @@ Please see LICENSE files in the repository root for full details.
*/ */
import { MockedObject } from "jest-mock"; import { MockedObject } from "jest-mock";
import { MatrixClient, MatrixEvent, EventType, Room, EventTimeline } from "matrix-js-sdk/src/matrix"; import { EventTimeline, EventType, MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types"; import { KnownMembership } from "matrix-js-sdk/src/types";
import { IRoomState } from "../../src/components/structures/RoomView"; import { IRoomState, MainSplitContentType } from "../../src/components/structures/RoomView";
import { TimelineRenderingType } from "../../src/contexts/RoomContext"; import { TimelineRenderingType } from "../../src/contexts/RoomContext";
import { Layout } from "../../src/settings/enums/Layout"; import { Layout } from "../../src/settings/enums/Layout";
import { mkEvent } from "./test-utils"; import { mkEvent } from "./test-utils";
@ -54,7 +54,6 @@ export function getRoomContext(room: Room, override: Partial<IRoomState>): IRoom
showApps: false, showApps: false,
isPeeking: false, isPeeking: false,
showRightPanel: true, showRightPanel: true,
threadRightPanel: false,
joining: false, joining: false,
atEndOfLiveTimeline: true, atEndOfLiveTimeline: true,
showTopUnreadMessagesBar: false, showTopUnreadMessagesBar: false,
@ -76,6 +75,7 @@ export function getRoomContext(room: Room, override: Partial<IRoomState>): IRoom
showDisplaynameChanges: true, showDisplaynameChanges: true,
matrixClientIsReady: false, matrixClientIsReady: false,
timelineRenderingType: TimelineRenderingType.Room, timelineRenderingType: TimelineRenderingType.Room,
mainSplitContentType: MainSplitContentType.Timeline,
liveTimeline: undefined, liveTimeline: undefined,
canSelfRedact: false, canSelfRedact: false,
resizing: false, resizing: false,

View file

@ -1893,10 +1893,10 @@
resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe" resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe"
integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q== integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==
"@matrix-org/analytics-events@^0.25.0": "@matrix-org/analytics-events@^0.26.0":
version "0.25.0" version "0.26.0"
resolved "https://registry.yarnpkg.com/@matrix-org/analytics-events/-/analytics-events-0.25.0.tgz#b0b85297dc05a67feaf89cc5d70b80283c988141" resolved "https://registry.yarnpkg.com/@matrix-org/analytics-events/-/analytics-events-0.26.0.tgz#7c8f8f924d8313c87951a0e941640ef8ff78f3d6"
integrity sha512-UCTuMjlJGArMqG9qXGfeNz/XtZDFldwuO+dkqP6Wo1nVdWasoWAOlcimDWQ2JnNFCg+UDZU+HLBdS5juTd6xTg== integrity sha512-cjKZBejajUG8wPhVygMkBTwTLdEn74luUP6g6RjCUqPR3RYIl3NVi58Zil8CWfRTILb4wVLCPpAvehgXJn1HnQ==
"@matrix-org/emojibase-bindings@^1.1.2": "@matrix-org/emojibase-bindings@^1.1.2":
version "1.1.3" version "1.1.3"
@ -9599,7 +9599,6 @@ which@^2.0.1:
isexe "^2.0.0" isexe "^2.0.0"
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
name wrap-ansi-cjs
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==