Merge branch 'develop' into germain-gg/fix-right-panel-member
This commit is contained in:
commit
4e6148d798
10 changed files with 306 additions and 15 deletions
|
@ -22,6 +22,7 @@ limitations under the License.
|
|||
border-radius: 10px;
|
||||
background-color: $secondary-hairline-color;
|
||||
user-select: none;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
border-color: $quinary-content;
|
||||
|
|
|
@ -18,6 +18,7 @@ limitations under the License.
|
|||
import React from "react";
|
||||
import { Direction, ConnectionError, MatrixError, HTTPError } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { capitalize } from "lodash";
|
||||
|
||||
import { _t, getUserLanguage } from "../../../languageHandler";
|
||||
import { formatFullDateNoDay, formatFullDateNoTime, getDaysArray } from "../../../DateUtils";
|
||||
|
@ -92,6 +93,10 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private get relativeTimeFormat(): Intl.RelativeTimeFormat {
|
||||
return new Intl.RelativeTimeFormat(getUserLanguage(), { style: "long", numeric: "auto" });
|
||||
}
|
||||
|
||||
private getLabel(): string {
|
||||
const date = new Date(this.props.ts);
|
||||
const disableRelativeTimestamps = !SettingsStore.getValue(UIFeature.TimelineEnableRelativeDates);
|
||||
|
@ -104,11 +109,10 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
const days = getDaysArray("long");
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
|
||||
const relativeTimeFormat = new Intl.RelativeTimeFormat(getUserLanguage(), { style: "long", numeric: "auto" });
|
||||
if (date.toDateString() === today.toDateString()) {
|
||||
return relativeTimeFormat.format(0, "day"); // Today
|
||||
return this.relativeTimeFormat.format(0, "day"); // Today
|
||||
} else if (date.toDateString() === yesterday.toDateString()) {
|
||||
return relativeTimeFormat.format(-1, "day"); // Yesterday
|
||||
return this.relativeTimeFormat.format(-1, "day"); // Yesterday
|
||||
} else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
|
||||
return days[date.getDay()]; // Sunday-Saturday
|
||||
} else {
|
||||
|
@ -263,6 +267,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
private renderJumpToDateMenu(): React.ReactElement {
|
||||
let contextMenu: JSX.Element | undefined;
|
||||
if (this.state.contextMenuPosition) {
|
||||
const relativeTimeFormat = this.relativeTimeFormat;
|
||||
contextMenu = (
|
||||
<IconizedContextMenu
|
||||
{...contextMenuBelow(this.state.contextMenuPosition)}
|
||||
|
@ -270,12 +275,12 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
>
|
||||
<IconizedContextMenuOptionList first>
|
||||
<IconizedContextMenuOption
|
||||
label={_t("time|last_week")}
|
||||
label={capitalize(relativeTimeFormat.format(-1, "week"))}
|
||||
onClick={this.onLastWeekClicked}
|
||||
data-testid="jump-to-date-last-week"
|
||||
/>
|
||||
<IconizedContextMenuOption
|
||||
label={_t("time|last_month")}
|
||||
label={capitalize(relativeTimeFormat.format(-1, "month"))}
|
||||
onClick={this.onLastMonthClicked}
|
||||
data-testid="jump-to-date-last-month"
|
||||
/>
|
||||
|
|
|
@ -18,6 +18,7 @@ import React, { SyntheticEvent } from "react";
|
|||
import classNames from "classnames";
|
||||
import { MatrixEvent, MatrixEventEvent, Relations, RelationsEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { uniqBy } from "lodash";
|
||||
import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { isContentActionable } from "../../../utils/EventUtils";
|
||||
|
@ -27,10 +28,13 @@ import ReactionPicker from "../emojipicker/ReactionPicker";
|
|||
import ReactionsRowButton from "./ReactionsRowButton";
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
|
||||
// The maximum number of reactions to initially show on a message.
|
||||
const MAX_ITEMS_WHEN_LIMITED = 8;
|
||||
|
||||
export const REACTION_SHORTCODE_KEY = new UnstableValue("shortcode", "com.beeper.reaction.shortcode");
|
||||
|
||||
const ReactButton: React.FC<IProps> = ({ mxEvent, reactions }) => {
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
|
||||
|
||||
|
@ -169,6 +173,7 @@ export default class ReactionsRow extends React.PureComponent<IProps, IState> {
|
|||
if (!reactions || !isContentActionable(mxEvent)) {
|
||||
return null;
|
||||
}
|
||||
const customReactionImagesEnabled = SettingsStore.getValue("feature_render_reaction_images");
|
||||
|
||||
let items = reactions
|
||||
.getSortedAnnotationsByKey()
|
||||
|
@ -195,6 +200,7 @@ export default class ReactionsRow extends React.PureComponent<IProps, IState> {
|
|||
mxEvent={mxEvent}
|
||||
reactionEvents={deduplicatedEvents}
|
||||
myReactionEvent={myReactionEvent}
|
||||
customReactionImagesEnabled={customReactionImagesEnabled}
|
||||
disabled={
|
||||
!this.context.canReact ||
|
||||
(myReactionEvent && !myReactionEvent.isRedacted() && !this.context.canSelfRedact)
|
||||
|
|
|
@ -18,13 +18,15 @@ import React from "react";
|
|||
import classNames from "classnames";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { mediaFromMxc } from "../../../customisations/Media";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { formatCommaSeparatedList } from "../../../utils/FormattingUtils";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import ReactionsRowButtonTooltip from "./ReactionsRowButtonTooltip";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
interface IProps {
|
||||
import { REACTION_SHORTCODE_KEY } from "./ReactionsRow";
|
||||
export interface IProps {
|
||||
// The event we're displaying reactions for
|
||||
mxEvent: MatrixEvent;
|
||||
// The reaction content / key / emoji
|
||||
|
@ -37,6 +39,8 @@ interface IProps {
|
|||
myReactionEvent?: MatrixEvent;
|
||||
// Whether to prevent quick-reactions by clicking on this reaction
|
||||
disabled?: boolean;
|
||||
// Whether to render custom image reactions
|
||||
customReactionImagesEnabled?: boolean;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -100,27 +104,56 @@ export default class ReactionsRowButton extends React.PureComponent<IProps, ISta
|
|||
content={content}
|
||||
reactionEvents={reactionEvents}
|
||||
visible={this.state.tooltipVisible}
|
||||
customReactionImagesEnabled={this.props.customReactionImagesEnabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const room = this.context.getRoom(mxEvent.getRoomId());
|
||||
let label: string | undefined;
|
||||
let customReactionName: string | undefined;
|
||||
if (room) {
|
||||
const senders: string[] = [];
|
||||
for (const reactionEvent of reactionEvents) {
|
||||
const member = room.getMember(reactionEvent.getSender()!);
|
||||
senders.push(member?.name || reactionEvent.getSender()!);
|
||||
customReactionName =
|
||||
(this.props.customReactionImagesEnabled &&
|
||||
REACTION_SHORTCODE_KEY.findIn(reactionEvent.getContent())) ||
|
||||
undefined;
|
||||
}
|
||||
|
||||
const reactors = formatCommaSeparatedList(senders, 6);
|
||||
if (content) {
|
||||
label = _t("%(reactors)s reacted with %(content)s", { reactors, content });
|
||||
label = _t("%(reactors)s reacted with %(content)s", {
|
||||
reactors,
|
||||
content: customReactionName || content,
|
||||
});
|
||||
} else {
|
||||
label = reactors;
|
||||
}
|
||||
}
|
||||
|
||||
let reactionContent = (
|
||||
<span className="mx_ReactionsRowButton_content" aria-hidden="true">
|
||||
{content}
|
||||
</span>
|
||||
);
|
||||
if (this.props.customReactionImagesEnabled && content.startsWith("mxc://")) {
|
||||
const imageSrc = mediaFromMxc(content).srcHttp;
|
||||
if (imageSrc) {
|
||||
reactionContent = (
|
||||
<img
|
||||
className="mx_ReactionsRowButton_content"
|
||||
alt={customReactionName || _t("Custom reaction")}
|
||||
src={imageSrc}
|
||||
width="16"
|
||||
height="16"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<AccessibleButton
|
||||
className={classes}
|
||||
|
@ -130,9 +163,7 @@ export default class ReactionsRowButton extends React.PureComponent<IProps, ISta
|
|||
onMouseOver={this.onMouseOver}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
>
|
||||
<span className="mx_ReactionsRowButton_content" aria-hidden="true">
|
||||
{content}
|
||||
</span>
|
||||
{reactionContent}
|
||||
<span className="mx_ReactionsRowButton_count" aria-hidden="true">
|
||||
{count}
|
||||
</span>
|
||||
|
|
|
@ -22,6 +22,7 @@ import { _t } from "../../../languageHandler";
|
|||
import { formatCommaSeparatedList } from "../../../utils/FormattingUtils";
|
||||
import Tooltip from "../elements/Tooltip";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { REACTION_SHORTCODE_KEY } from "./ReactionsRow";
|
||||
interface IProps {
|
||||
// The event we're displaying reactions for
|
||||
mxEvent: MatrixEvent;
|
||||
|
@ -30,6 +31,8 @@ interface IProps {
|
|||
// A list of Matrix reaction events for this key
|
||||
reactionEvents: MatrixEvent[];
|
||||
visible: boolean;
|
||||
// Whether to render custom image reactions
|
||||
customReactionImagesEnabled?: boolean;
|
||||
}
|
||||
|
||||
export default class ReactionsRowButtonTooltip extends React.PureComponent<IProps> {
|
||||
|
@ -43,12 +46,17 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent<IProp
|
|||
let tooltipLabel: JSX.Element | undefined;
|
||||
if (room) {
|
||||
const senders: string[] = [];
|
||||
let customReactionName: string | undefined;
|
||||
for (const reactionEvent of reactionEvents) {
|
||||
const member = room.getMember(reactionEvent.getSender()!);
|
||||
const name = member?.name ?? reactionEvent.getSender()!;
|
||||
senders.push(name);
|
||||
customReactionName =
|
||||
(this.props.customReactionImagesEnabled &&
|
||||
REACTION_SHORTCODE_KEY.findIn(reactionEvent.getContent())) ||
|
||||
undefined;
|
||||
}
|
||||
const shortName = unicodeToShortcode(content);
|
||||
const shortName = unicodeToShortcode(content) || customReactionName;
|
||||
tooltipLabel = (
|
||||
<div>
|
||||
{_t(
|
||||
|
|
|
@ -480,6 +480,7 @@ export interface IProps {
|
|||
interface IState {
|
||||
contextMenuPosition?: DOMRect;
|
||||
rightPanelOpen: boolean;
|
||||
featureAskToJoin: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -496,6 +497,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
public static contextType = RoomContext;
|
||||
public context!: React.ContextType<typeof RoomContext>;
|
||||
private readonly client = this.props.room.client;
|
||||
private readonly featureAskToJoinWatcher: string;
|
||||
|
||||
public constructor(props: IProps, context: IState) {
|
||||
super(props, context);
|
||||
|
@ -503,7 +505,15 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
notiStore.on(NotificationStateEvents.Update, this.onNotificationUpdate);
|
||||
this.state = {
|
||||
rightPanelOpen: RightPanelStore.instance.isOpen,
|
||||
featureAskToJoin: SettingsStore.getValue("feature_ask_to_join"),
|
||||
};
|
||||
this.featureAskToJoinWatcher = SettingsStore.watchSetting(
|
||||
"feature_ask_to_join",
|
||||
null,
|
||||
(_settingName, _roomId, _atLevel, _newValAtLevel, featureAskToJoin) => {
|
||||
this.setState({ featureAskToJoin });
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
|
@ -516,6 +526,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
const notiStore = RoomNotificationStateStore.instance.getRoomState(this.props.room);
|
||||
notiStore.removeListener(NotificationStateEvents.Update, this.onNotificationUpdate);
|
||||
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
SettingsStore.unwatchSetting(this.featureAskToJoinWatcher);
|
||||
}
|
||||
|
||||
private onRightPanelStoreUpdate = (): void => {
|
||||
|
@ -821,7 +832,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
</div>
|
||||
{!isVideoRoom && <RoomCallBanner roomId={this.props.room.roomId} />}
|
||||
<RoomLiveShareWarning roomId={this.props.room.roomId} />
|
||||
<RoomKnocksBar room={this.props.room} />
|
||||
{this.state.featureAskToJoin && <RoomKnocksBar room={this.props.room} />}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -218,9 +218,7 @@
|
|||
"short_seconds": "%(value)ss",
|
||||
"short_days_hours_minutes_seconds": "%(days)sd %(hours)sh %(minutes)sm %(seconds)ss",
|
||||
"short_hours_minutes_seconds": "%(hours)sh %(minutes)sm %(seconds)ss",
|
||||
"short_minutes_seconds": "%(minutes)sm %(seconds)ss",
|
||||
"last_week": "Last week",
|
||||
"last_month": "Last month"
|
||||
"short_minutes_seconds": "%(minutes)sm %(seconds)ss"
|
||||
},
|
||||
"Identity server has no terms of service": "Identity server has no terms of service",
|
||||
"This action requires accessing the default identity server <server /> to validate an email address or phone number, but the server does not have any terms of service.": "This action requires accessing the default identity server <server /> to validate an email address or phone number, but the server does not have any terms of service.",
|
||||
|
@ -948,6 +946,8 @@
|
|||
"Force 15s voice broadcast chunk length": "Force 15s voice broadcast chunk length",
|
||||
"Enable new native OIDC flows (Under active development)": "Enable new native OIDC flows (Under active development)",
|
||||
"Font size": "Font size",
|
||||
"Render custom images in reactions": "Render custom images in reactions",
|
||||
"Sometimes referred to as \"custom emojis\".": "Sometimes referred to as \"custom emojis\".",
|
||||
"Use custom size": "Use custom size",
|
||||
"Show polls button": "Show polls button",
|
||||
"Use a more compact 'Modern' layout": "Use a more compact 'Modern' layout",
|
||||
|
@ -2316,6 +2316,7 @@
|
|||
"Error processing voice message": "Error processing voice message",
|
||||
"Add reaction": "Add reaction",
|
||||
"%(reactors)s reacted with %(content)s": "%(reactors)s reacted with %(content)s",
|
||||
"Custom reaction": "Custom reaction",
|
||||
"<reactors/><reactedWith>reacted with %(shortName)s</reactedWith>": "<reactors/><reactedWith>reacted with %(shortName)s</reactedWith>",
|
||||
"Message deleted on %(date)s": "Message deleted on %(date)s",
|
||||
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s",
|
||||
|
|
|
@ -472,6 +472,14 @@ export const SETTINGS: { [setting: string]: ISetting } = {
|
|||
default: "",
|
||||
controller: new FontSizeController(),
|
||||
},
|
||||
"feature_render_reaction_images": {
|
||||
isFeature: true,
|
||||
labsGroup: LabGroup.Messaging,
|
||||
displayName: _td("Render custom images in reactions"),
|
||||
description: _td('Sometimes referred to as "custom emojis".'),
|
||||
supportedLevels: LEVELS_FEATURE,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* With the transition to Compound we are moving to a base font size
|
||||
* of 16px. We're taking the opportunity to move away from the `baseFontSize`
|
||||
|
|
119
test/components/views/messages/ReactionsRowButton-test.tsx
Normal file
119
test/components/views/messages/ReactionsRowButton-test.tsx
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Copyright 2023 Beeper
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { IContent, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
import ReactionsRowButton, { IProps } from "../../../../src/components/views/messages/ReactionsRowButton";
|
||||
|
||||
describe("ReactionsRowButton", () => {
|
||||
const userId = "@alice:server";
|
||||
const roomId = "!randomcharacters:aser.ver";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue("https://not.a.real.url"),
|
||||
getRoom: jest.fn(),
|
||||
});
|
||||
const room = new Room(roomId, mockClient, userId);
|
||||
|
||||
const createProps = (relationContent: IContent): IProps => ({
|
||||
mxEvent: new MatrixEvent({
|
||||
room_id: roomId,
|
||||
event_id: "$test:example.com",
|
||||
content: { body: "test" },
|
||||
}),
|
||||
content: relationContent["m.relates_to"]?.key || "",
|
||||
count: 2,
|
||||
reactionEvents: [
|
||||
new MatrixEvent({
|
||||
type: "m.reaction",
|
||||
sender: "@user1:example.com",
|
||||
content: relationContent,
|
||||
}),
|
||||
new MatrixEvent({
|
||||
type: "m.reaction",
|
||||
sender: "@user2:example.com",
|
||||
content: relationContent,
|
||||
}),
|
||||
],
|
||||
customReactionImagesEnabled: true,
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
jest.clearAllMocks();
|
||||
mockClient.credentials = { userId: userId };
|
||||
mockClient.getRoom.mockImplementation((roomId: string): Room | null => {
|
||||
return roomId === room.roomId ? room : null;
|
||||
});
|
||||
});
|
||||
|
||||
it("renders reaction row button emojis correctly", () => {
|
||||
const props = createProps({
|
||||
"m.relates_to": {
|
||||
event_id: "$user2:example.com",
|
||||
key: "👍",
|
||||
rel_type: "m.annotation",
|
||||
},
|
||||
});
|
||||
const root = render(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<ReactionsRowButton {...props} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
expect(root.asFragment()).toMatchSnapshot();
|
||||
|
||||
// Try hover and make sure that the ReactionsRowButtonTooltip works
|
||||
const reactionButton = root.getByRole("button");
|
||||
const event = new MouseEvent("mouseover", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
reactionButton.dispatchEvent(event);
|
||||
|
||||
expect(root.asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders reaction row button custom image reactions correctly", () => {
|
||||
const props = createProps({
|
||||
"com.beeper.reaction.shortcode": ":test:",
|
||||
"shortcode": ":test:",
|
||||
"m.relates_to": {
|
||||
event_id: "$user1:example.com",
|
||||
key: "mxc://example.com/123456789",
|
||||
rel_type: "m.annotation",
|
||||
},
|
||||
});
|
||||
|
||||
const root = render(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<ReactionsRowButton {...props} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
expect(root.asFragment()).toMatchSnapshot();
|
||||
|
||||
// Try hover and make sure that the ReactionsRowButtonTooltip works
|
||||
const reactionButton = root.getByRole("button");
|
||||
const event = new MouseEvent("mouseover", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
reactionButton.dispatchEvent(event);
|
||||
|
||||
expect(root.asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,101 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ReactionsRowButton renders reaction row button custom image reactions correctly 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
aria-label="@user1:example.com and @user2:example.com reacted with :test:"
|
||||
class="mx_AccessibleButton mx_ReactionsRowButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<img
|
||||
alt=":test:"
|
||||
class="mx_ReactionsRowButton_content"
|
||||
height="16"
|
||||
src="https://not.a.real.url"
|
||||
width="16"
|
||||
/>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="mx_ReactionsRowButton_count"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`ReactionsRowButton renders reaction row button custom image reactions correctly 2`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
aria-label="@user1:example.com and @user2:example.com reacted with :test:"
|
||||
class="mx_AccessibleButton mx_ReactionsRowButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<img
|
||||
alt=":test:"
|
||||
class="mx_ReactionsRowButton_content"
|
||||
height="16"
|
||||
src="https://not.a.real.url"
|
||||
width="16"
|
||||
/>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="mx_ReactionsRowButton_count"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
<div />
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`ReactionsRowButton renders reaction row button emojis correctly 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
aria-label="@user1:example.com and @user2:example.com reacted with 👍"
|
||||
class="mx_AccessibleButton mx_ReactionsRowButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="mx_ReactionsRowButton_content"
|
||||
>
|
||||
👍
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="mx_ReactionsRowButton_count"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`ReactionsRowButton renders reaction row button emojis correctly 2`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
aria-label="@user1:example.com and @user2:example.com reacted with 👍"
|
||||
class="mx_AccessibleButton mx_ReactionsRowButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="mx_ReactionsRowButton_content"
|
||||
>
|
||||
👍
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="mx_ReactionsRowButton_count"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
<div />
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
Loading…
Reference in a new issue