Iterate landmarks around the app in order to improve a11y (#12064)
* Iterate landmarks around the app in order to improve a11y Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add missing aria-label Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update screenshots which have changed a fraction due to default heading margins being different in different landmarks Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>pull/28788/head^2
|
@ -25,7 +25,7 @@ test.describe("UserView", () => {
|
||||||
test("should render the user view as expected", async ({ page, homeserver, user, bot }) => {
|
test("should render the user view as expected", async ({ page, homeserver, user, bot }) => {
|
||||||
await page.goto(`/#/user/${bot.credentials.userId}`);
|
await page.goto(`/#/user/${bot.credentials.userId}`);
|
||||||
|
|
||||||
const rightPanel = page.getByRole("complementary");
|
const rightPanel = page.locator("#mx_RightPanel");
|
||||||
await expect(rightPanel.getByRole("heading", { name: bot.credentials.displayName, exact: true })).toBeVisible();
|
await expect(rightPanel.getByRole("heading", { name: bot.credentials.displayName, exact: true })).toBeVisible();
|
||||||
await expect(rightPanel.getByText("1 session")).toBeVisible();
|
await expect(rightPanel.getByText("1 session")).toBeVisible();
|
||||||
await expect(rightPanel).toMatchScreenshot("user-info.png", {
|
await expect(rightPanel).toMatchScreenshot("user-info.png", {
|
||||||
|
|
|
@ -90,11 +90,11 @@ export class Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open room settings (via room menu), returns a locator to the dialog
|
* Open room settings (via room header menu), returns a locator to the dialog
|
||||||
* @param tab the name of the tab to switch to after opening, optional.
|
* @param tab the name of the tab to switch to after opening, optional.
|
||||||
*/
|
*/
|
||||||
public async openRoomSettings(tab?: string): Promise<Locator> {
|
public async openRoomSettings(tab?: string): Promise<Locator> {
|
||||||
await this.page.getByRole("main").getByRole("button", { name: "Room options", exact: true }).click();
|
await this.page.getByRole("banner").getByRole("button", { name: "Room options", exact: true }).click();
|
||||||
await this.page.locator(".mx_RoomTile_contextMenu").getByRole("menuitem", { name: "Settings" }).click();
|
await this.page.locator(".mx_RoomTile_contextMenu").getByRole("menuitem", { name: "Settings" }).click();
|
||||||
if (tab) await this.switchTab(tab);
|
if (tab) await this.switchTab(tab);
|
||||||
return this.page.locator(".mx_Dialog").filter({ has: this.page.locator(".mx_RoomSettingsDialog") });
|
return this.page.locator(".mx_Dialog").filter({ has: this.page.locator(".mx_RoomSettingsDialog") });
|
||||||
|
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 563 KiB After Width: | Height: | Size: 563 KiB |
|
@ -315,6 +315,8 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
if (this.state.showBreadcrumbs === BreadcrumbsMode.Legacy && !this.props.isMinimized) {
|
if (this.state.showBreadcrumbs === BreadcrumbsMode.Legacy && !this.props.isMinimized) {
|
||||||
return (
|
return (
|
||||||
<IndicatorScrollbar
|
<IndicatorScrollbar
|
||||||
|
role="navigation"
|
||||||
|
aria-label={_t("a11y|recent_rooms")}
|
||||||
className="mx_LeftPanel_breadcrumbsContainer mx_AutoHideScrollbar"
|
className="mx_LeftPanel_breadcrumbsContainer mx_AutoHideScrollbar"
|
||||||
verticalScrollsHorizontally={true}
|
verticalScrollsHorizontally={true}
|
||||||
>
|
>
|
||||||
|
@ -356,6 +358,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
|
role="search"
|
||||||
>
|
>
|
||||||
<RoomSearch isMinimized={this.props.isMinimized} />
|
<RoomSearch isMinimized={this.props.isMinimized} />
|
||||||
|
|
||||||
|
@ -397,7 +400,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
selected={this.props.pageType === PageType.HomePage}
|
selected={this.props.pageType === PageType.HomePage}
|
||||||
minimized={this.props.isMinimized}
|
minimized={this.props.isMinimized}
|
||||||
/>
|
/>
|
||||||
<div className="mx_LeftPanel_roomListWrapper">
|
<nav className="mx_LeftPanel_roomListWrapper" aria-label={_t("common|rooms")}>
|
||||||
<div
|
<div
|
||||||
className={roomListClasses}
|
className={roomListClasses}
|
||||||
ref={this.listContainerRef}
|
ref={this.listContainerRef}
|
||||||
|
@ -407,7 +410,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
>
|
>
|
||||||
{roomList}
|
{roomList}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -683,7 +683,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
<div className={bodyClasses}>
|
<div className={bodyClasses}>
|
||||||
<div className="mx_LeftPanel_outerWrapper">
|
<div className="mx_LeftPanel_outerWrapper">
|
||||||
<LeftPanelLiveShareWarning isMinimized={this.props.collapseLhs || false} />
|
<LeftPanelLiveShareWarning isMinimized={this.props.collapseLhs || false} />
|
||||||
<nav className="mx_LeftPanel_wrapper">
|
<div className="mx_LeftPanel_wrapper">
|
||||||
<BackdropPanel blurMultiplier={0.5} backgroundImage={this.state.backgroundImage} />
|
<BackdropPanel blurMultiplier={0.5} backgroundImage={this.state.backgroundImage} />
|
||||||
<SpacePanel />
|
<SpacePanel />
|
||||||
<BackdropPanel backgroundImage={this.state.backgroundImage} />
|
<BackdropPanel backgroundImage={this.state.backgroundImage} />
|
||||||
|
@ -698,7 +698,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ResizeHandle passRef={this.resizeHandler} id="lp-resizer" />
|
<ResizeHandle passRef={this.resizeHandler} id="lp-resizer" />
|
||||||
<div className="mx_RoomView_wrapper">{pageElement}</div>
|
<div className="mx_RoomView_wrapper">{pageElement}</div>
|
||||||
|
|
|
@ -406,7 +406,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
private unmounted = false;
|
private unmounted = false;
|
||||||
private permalinkCreators: Record<string, RoomPermalinkCreator> = {};
|
private permalinkCreators: Record<string, RoomPermalinkCreator> = {};
|
||||||
|
|
||||||
private roomView = createRef<HTMLElement>();
|
private roomView = createRef<HTMLDivElement>();
|
||||||
private searchResultsPanel = createRef<ScrollPanel>();
|
private searchResultsPanel = createRef<ScrollPanel>();
|
||||||
private messagePanel: TimelinePanel | null = null;
|
private messagePanel: TimelinePanel | null = null;
|
||||||
private roomViewBody = createRef<HTMLDivElement>();
|
private roomViewBody = createRef<HTMLDivElement>();
|
||||||
|
@ -2302,7 +2302,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
// if statusBar does not exist then statusBarArea is blank and takes up unnecessary space on the screen
|
// if statusBar does not exist then statusBarArea is blank and takes up unnecessary space on the screen
|
||||||
// show statusBarArea only if statusBar is present
|
// show statusBarArea only if statusBar is present
|
||||||
const statusBarArea = statusBar && (
|
const statusBarArea = statusBar && (
|
||||||
<div className={statusBarAreaClass}>
|
<div role="region" className={statusBarAreaClass} aria-label={_t("a11y|room_status_bar")}>
|
||||||
<div className="mx_RoomView_statusAreaBox">
|
<div className="mx_RoomView_statusAreaBox">
|
||||||
<div className="mx_RoomView_statusAreaBox_line" />
|
<div className="mx_RoomView_statusAreaBox_line" />
|
||||||
{statusBar}
|
{statusBar}
|
||||||
|
@ -2528,13 +2528,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
<Measured sensor={this.roomViewBody.current} onMeasurement={this.onMeasurement} />
|
<Measured sensor={this.roomViewBody.current} onMeasurement={this.onMeasurement} />
|
||||||
)}
|
)}
|
||||||
{auxPanel}
|
{auxPanel}
|
||||||
<div className={timelineClasses}>
|
<main className={timelineClasses}>
|
||||||
<FileDropTarget parent={this.roomView.current} onFileDrop={this.onFileDrop} />
|
<FileDropTarget parent={this.roomView.current} onFileDrop={this.onFileDrop} />
|
||||||
{topUnreadMessagesBar}
|
{topUnreadMessagesBar}
|
||||||
{jumpToBottom}
|
{jumpToBottom}
|
||||||
{messagePanel}
|
{messagePanel}
|
||||||
{searchResultsPanel}
|
{searchResultsPanel}
|
||||||
</div>
|
</main>
|
||||||
{statusBarArea}
|
{statusBarArea}
|
||||||
{previewBar}
|
{previewBar}
|
||||||
{messageComposer}
|
{messageComposer}
|
||||||
|
@ -2550,6 +2550,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
userId={this.context.client.getSafeUserId()}
|
userId={this.context.client.getSafeUserId()}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
showApps={true}
|
showApps={true}
|
||||||
|
role="main"
|
||||||
/>
|
/>
|
||||||
{previewBar}
|
{previewBar}
|
||||||
</>
|
</>
|
||||||
|
@ -2563,6 +2564,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
resizing={this.state.resizing}
|
resizing={this.state.resizing}
|
||||||
waitForCall={isVideoRoom(this.state.room)}
|
waitForCall={isVideoRoom(this.state.room)}
|
||||||
|
role="main"
|
||||||
/>
|
/>
|
||||||
{previewBar}
|
{previewBar}
|
||||||
</>
|
</>
|
||||||
|
@ -2603,7 +2605,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RoomContext.Provider value={this.state}>
|
<RoomContext.Provider value={this.state}>
|
||||||
<main
|
<div
|
||||||
className={mainClasses}
|
className={mainClasses}
|
||||||
ref={this.roomView}
|
ref={this.roomView}
|
||||||
onKeyDown={this.onReactKeyDown}
|
onKeyDown={this.onReactKeyDown}
|
||||||
|
@ -2655,7 +2657,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
</div>
|
</div>
|
||||||
</MainSplit>
|
</MainSplit>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</main>
|
</div>
|
||||||
</RoomContext.Provider>
|
</RoomContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,11 +180,11 @@ const EmptyThread: React.FC<EmptyThreadIProps> = ({ hasThreads, filterOption, sh
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="mx_ThreadPanel_empty">
|
<div className="mx_ThreadPanel_empty">
|
||||||
<div className="mx_ThreadPanel_largeIcon" />
|
<div className="mx_ThreadPanel_largeIcon" />
|
||||||
<h2>{_t("threads|empty_heading")}</h2>
|
<h2>{_t("threads|empty_heading")}</h2>
|
||||||
{body}
|
{body}
|
||||||
</aside>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -362,7 +362,12 @@ class EmojiPicker extends React.Component<IProps, IState> {
|
||||||
{({ onKeyDownHandler }) => {
|
{({ onKeyDownHandler }) => {
|
||||||
let heightBefore = 0;
|
let heightBefore = 0;
|
||||||
return (
|
return (
|
||||||
<div className="mx_EmojiPicker" data-testid="mx_EmojiPicker" onKeyDown={onKeyDownHandler}>
|
<section
|
||||||
|
className="mx_EmojiPicker"
|
||||||
|
data-testid="mx_EmojiPicker"
|
||||||
|
onKeyDown={onKeyDownHandler}
|
||||||
|
aria-label={_t("a11y|emoji_picker")}
|
||||||
|
>
|
||||||
<Header categories={this.categories} onAnchorClick={this.scrollToCategory} />
|
<Header categories={this.categories} onAnchorClick={this.scrollToCategory} />
|
||||||
<Search
|
<Search
|
||||||
query={this.state.filter}
|
query={this.state.filter}
|
||||||
|
@ -407,7 +412,7 @@ class EmojiPicker extends React.Component<IProps, IState> {
|
||||||
selectedEmojis={this.props.selectedEmojis}
|
selectedEmojis={this.props.selectedEmojis}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</RovingTabIndexProvider>
|
</RovingTabIndexProvider>
|
||||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { AriaRole } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Resizable, Size } from "re-resizable";
|
import { Resizable, Size } from "re-resizable";
|
||||||
import { Room } from "matrix-js-sdk/src/matrix";
|
import { Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
@ -42,6 +42,7 @@ interface IProps {
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
showApps?: boolean; // Should apps be rendered
|
showApps?: boolean; // Should apps be rendered
|
||||||
maxHeight: number;
|
maxHeight: number;
|
||||||
|
role?: AriaRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -294,7 +295,7 @@ export default class AppsDrawer extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes}>
|
<div role={this.props.role} className={classes}>
|
||||||
{drawer}
|
{drawer}
|
||||||
{spinner}
|
{spinner}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default class AuxPanel extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoHideScrollbar className="mx_AuxPanel">
|
<AutoHideScrollbar role="region" className="mx_AuxPanel">
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
{appsDrawer}
|
{appsDrawer}
|
||||||
{callView}
|
{callView}
|
||||||
|
|
|
@ -602,6 +602,8 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||||
className={classes}
|
className={classes}
|
||||||
ref={this.ref}
|
ref={this.ref}
|
||||||
aria-describedby={this.state.recordingTimeLeftSeconds ? this.tooltipId : undefined}
|
aria-describedby={this.state.recordingTimeLeftSeconds ? this.tooltipId : undefined}
|
||||||
|
role="region"
|
||||||
|
aria-label={_t("a11y|message_composer")}
|
||||||
>
|
>
|
||||||
{recordingTooltip}
|
{recordingTooltip}
|
||||||
<div className="mx_MessageComposer_wrapper">
|
<div className="mx_MessageComposer_wrapper">
|
||||||
|
|
|
@ -182,7 +182,7 @@ export default function RoomHeader({
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</button>
|
</button>
|
||||||
<Flex as="nav" align="center" gap="var(--cpd-space-2x)">
|
<Flex align="center" gap="var(--cpd-space-2x)">
|
||||||
{additionalButtons?.map((props) => {
|
{additionalButtons?.map((props) => {
|
||||||
const label = props.label();
|
const label = props.label();
|
||||||
|
|
||||||
|
|
|
@ -409,7 +409,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomListHeader">
|
<aside className="mx_RoomListHeader" aria-label={_t("room|context_menu|title")}>
|
||||||
{contextMenuButton}
|
{contextMenuButton}
|
||||||
{pendingActionSummary ? (
|
{pendingActionSummary ? (
|
||||||
<TooltipTarget label={pendingActionSummary}>
|
<TooltipTarget label={pendingActionSummary}>
|
||||||
|
@ -427,7 +427,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{contextMenu}
|
{contextMenu}
|
||||||
</div>
|
</aside>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -720,7 +720,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes}>
|
<div role="complementary" className={classes}>
|
||||||
<div className="mx_RoomPreviewBar_message">
|
<div className="mx_RoomPreviewBar_message">
|
||||||
{titleElement}
|
{titleElement}
|
||||||
{subTitleElements}
|
{subTitleElements}
|
||||||
|
|
|
@ -364,10 +364,11 @@ const SpacePanel: React.FC = () => {
|
||||||
onDragEndHandler();
|
onDragEndHandler();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<nav
|
||||||
className={classNames("mx_SpacePanel", { collapsed: isPanelCollapsed })}
|
className={classNames("mx_SpacePanel", { collapsed: isPanelCollapsed })}
|
||||||
onKeyDown={onKeyDownHandler}
|
onKeyDown={onKeyDownHandler}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
aria-label={_t("common|spaces")}
|
||||||
>
|
>
|
||||||
<UserMenu isPanelCollapsed={isPanelCollapsed}>
|
<UserMenu isPanelCollapsed={isPanelCollapsed}>
|
||||||
<AccessibleTooltipButton
|
<AccessibleTooltipButton
|
||||||
|
@ -406,7 +407,7 @@ const SpacePanel: React.FC = () => {
|
||||||
</Droppable>
|
</Droppable>
|
||||||
|
|
||||||
<QuickSettingsButton isPanelCollapsed={isPanelCollapsed} />
|
<QuickSettingsButton isPanelCollapsed={isPanelCollapsed} />
|
||||||
</div>
|
</nav>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
)}
|
)}
|
||||||
</RovingTabIndexProvider>
|
</RovingTabIndexProvider>
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, ReactNode, useState, useContext, useEffect, useMemo, useRef, useCallback } from "react";
|
import React, { FC, ReactNode, useState, useContext, useEffect, useMemo, useRef, useCallback, AriaRole } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { defer, IDeferred } from "matrix-js-sdk/src/utils";
|
import { defer, IDeferred } from "matrix-js-sdk/src/utils";
|
||||||
|
@ -297,9 +297,10 @@ interface StartCallViewProps {
|
||||||
resizing: boolean;
|
resizing: boolean;
|
||||||
call: Call | null;
|
call: Call | null;
|
||||||
setStartingCall: (value: boolean) => void;
|
setStartingCall: (value: boolean) => void;
|
||||||
|
role?: AriaRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StartCallView: FC<StartCallViewProps> = ({ room, resizing, call, setStartingCall }) => {
|
const StartCallView: FC<StartCallViewProps> = ({ room, resizing, call, setStartingCall, role }) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
// Since connection has to be split across two different callbacks, we
|
// Since connection has to be split across two different callbacks, we
|
||||||
|
@ -348,7 +349,7 @@ const StartCallView: FC<StartCallViewProps> = ({ room, resizing, call, setStarti
|
||||||
}, [call, connectDeferred]);
|
}, [call, connectDeferred]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_CallView">
|
<div className="mx_CallView" role={role}>
|
||||||
{connected ? null : <Lobby room={room} connect={connect} />}
|
{connected ? null : <Lobby room={room} connect={connect} />}
|
||||||
{call !== null && (
|
{call !== null && (
|
||||||
<AppTile
|
<AppTile
|
||||||
|
@ -369,9 +370,10 @@ interface JoinCallViewProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
resizing: boolean;
|
resizing: boolean;
|
||||||
call: Call;
|
call: Call;
|
||||||
|
role?: AriaRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call }) => {
|
const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call, role }) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
const connected = isConnected(useConnectionState(call));
|
const connected = isConnected(useConnectionState(call));
|
||||||
const members = useParticipatingMembers(call);
|
const members = useParticipatingMembers(call);
|
||||||
|
@ -415,7 +417,7 @@ const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_CallView">
|
<div className="mx_CallView" role={role}>
|
||||||
{lobby}
|
{lobby}
|
||||||
{/* We render the widget even if we're disconnected, so it stays loaded */}
|
{/* We render the widget even if we're disconnected, so it stays loaded */}
|
||||||
<AppTile
|
<AppTile
|
||||||
|
@ -439,16 +441,19 @@ interface CallViewProps {
|
||||||
* button will create a call if there isn't already one.
|
* button will create a call if there isn't already one.
|
||||||
*/
|
*/
|
||||||
waitForCall: boolean;
|
waitForCall: boolean;
|
||||||
|
role?: AriaRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CallView: FC<CallViewProps> = ({ room, resizing, waitForCall }) => {
|
export const CallView: FC<CallViewProps> = ({ room, resizing, waitForCall, role }) => {
|
||||||
const call = useCall(room.roomId);
|
const call = useCall(room.roomId);
|
||||||
const [startingCall, setStartingCall] = useState(false);
|
const [startingCall, setStartingCall] = useState(false);
|
||||||
|
|
||||||
if (call === null || startingCall) {
|
if (call === null || startingCall) {
|
||||||
if (waitForCall) return null;
|
if (waitForCall) return null;
|
||||||
return <StartCallView room={room} resizing={resizing} call={call} setStartingCall={setStartingCall} />;
|
return (
|
||||||
|
<StartCallView room={room} resizing={resizing} call={call} setStartingCall={setStartingCall} role={role} />
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return <JoinCallView room={room} resizing={resizing} call={call} />;
|
return <JoinCallView room={room} resizing={resizing} call={call} role={role} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"a11y": {
|
"a11y": {
|
||||||
|
"emoji_picker": "Emoji picker",
|
||||||
"jump_first_invite": "Jump to first invite.",
|
"jump_first_invite": "Jump to first invite.",
|
||||||
|
"message_composer": "Message composer",
|
||||||
"n_unread_messages": {
|
"n_unread_messages": {
|
||||||
"one": "1 unread message.",
|
"one": "1 unread message.",
|
||||||
"other": "%(count)s unread messages."
|
"other": "%(count)s unread messages."
|
||||||
|
@ -9,7 +11,9 @@
|
||||||
"one": "1 unread mention.",
|
"one": "1 unread mention.",
|
||||||
"other": "%(count)s unread messages including mentions."
|
"other": "%(count)s unread messages including mentions."
|
||||||
},
|
},
|
||||||
|
"recent_rooms": "Recent rooms",
|
||||||
"room_name": "Room %(name)s",
|
"room_name": "Room %(name)s",
|
||||||
|
"room_status_bar": "Room status bar",
|
||||||
"unread_messages": "Unread messages.",
|
"unread_messages": "Unread messages.",
|
||||||
"user_menu": "User menu"
|
"user_menu": "User menu"
|
||||||
},
|
},
|
||||||
|
|
|
@ -164,7 +164,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
<title>${_t("export_chat|html_title")}</title>
|
<title>${_t("export_chat|html_title")}</title>
|
||||||
</head>
|
</head>
|
||||||
<body style="height: 100vh;">
|
<body style="height: 100vh;">
|
||||||
<section
|
<div
|
||||||
id="matrixchat"
|
id="matrixchat"
|
||||||
style="height: 100%; overflow: auto"
|
style="height: 100%; overflow: auto"
|
||||||
class="notranslate"
|
class="notranslate"
|
||||||
|
@ -237,7 +237,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
<div id="snackbar"/>
|
<div id="snackbar"/>
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
|
|
|
@ -373,7 +373,9 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
aria-label="Message composer"
|
||||||
class="mx_MessageComposer"
|
class="mx_MessageComposer"
|
||||||
|
role="region"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_MessageComposer_wrapper"
|
class="mx_MessageComposer_wrapper"
|
||||||
|
@ -614,7 +616,9 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
aria-label="Message composer"
|
||||||
class="mx_MessageComposer"
|
class="mx_MessageComposer"
|
||||||
|
role="region"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_MessageComposer_wrapper"
|
class="mx_MessageComposer_wrapper"
|
||||||
|
@ -740,6 +744,7 @@ exports[`RoomView should show error view if failed to look up room alias 1`] = `
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_RoomPreviewBar mx_RoomPreviewBar_RoomNotFound mx_RoomPreviewBar_dialog"
|
class="mx_RoomPreviewBar mx_RoomPreviewBar_RoomNotFound mx_RoomPreviewBar_dialog"
|
||||||
|
role="complementary"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_RoomPreviewBar_message"
|
class="mx_RoomPreviewBar_message"
|
||||||
|
|
|
@ -39,7 +39,7 @@ exports[`RoomHeader does not show the face pile for DMs 1`] = `
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<nav
|
<div
|
||||||
class="mx_Flex"
|
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);"
|
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
|
||||||
>
|
>
|
||||||
|
@ -75,7 +75,7 @@ exports[`RoomHeader does not show the face pile for DMs 1`] = `
|
||||||
>
|
>
|
||||||
<div />
|
<div />
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</DocumentFragment>
|
</DocumentFragment>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -13,7 +13,7 @@ exports[`HTMLExport should export 1`] = `
|
||||||
<title>Exported Data</title>
|
<title>Exported Data</title>
|
||||||
</head>
|
</head>
|
||||||
<body style="height: 100vh;">
|
<body style="height: 100vh;">
|
||||||
<section
|
<div
|
||||||
id="matrixchat"
|
id="matrixchat"
|
||||||
style="height: 100%; overflow: auto"
|
style="height: 100%; overflow: auto"
|
||||||
class="notranslate"
|
class="notranslate"
|
||||||
|
@ -82,7 +82,7 @@ exports[`HTMLExport should export 1`] = `
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
<div id="snackbar"/>
|
<div id="snackbar"/>
|
||||||
</body>
|
</body>
|
||||||
</html>"
|
</html>"
|
||||||
|
|