mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-18 18:59:23 +00:00
Add keyboard shortcuts for reaction sending.
This commit is contained in:
@@ -1,15 +1,24 @@
|
|||||||
import { act, render } from "@testing-library/react";
|
/*
|
||||||
|
Copyright 2024 New Vector Ltd.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { act, fireEvent, render } from "@testing-library/react";
|
||||||
import { expect, test } from "vitest";
|
import { expect, test } from "vitest";
|
||||||
|
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
|
||||||
|
import { TooltipProvider } from "@vector-im/compound-web";
|
||||||
|
import { userEvent } from "@testing-library/user-event";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MockRoom,
|
MockRoom,
|
||||||
MockRTCSession,
|
MockRTCSession,
|
||||||
TestReactionsWrapper,
|
TestReactionsWrapper,
|
||||||
} from "../utils/testReactions";
|
} from "../utils/testReactions";
|
||||||
import { ReactionToggleButton } from "./ReactionToggleButton";
|
import { ReactionToggleButton } from "./ReactionToggleButton";
|
||||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
|
|
||||||
import { TooltipProvider } from "@vector-im/compound-web";
|
|
||||||
import { ElementCallReactionEventType } from "../reactions";
|
import { ElementCallReactionEventType } from "../reactions";
|
||||||
import { userEvent } from "@testing-library/user-event";
|
|
||||||
|
|
||||||
const memberUserIdAlice = "@alice:example.org";
|
const memberUserIdAlice = "@alice:example.org";
|
||||||
const memberEventAlice = "$membership-alice:example.org";
|
const memberEventAlice = "$membership-alice:example.org";
|
||||||
@@ -24,20 +33,20 @@ function TestComponent({
|
|||||||
}: {
|
}: {
|
||||||
rtcSession: MockRTCSession;
|
rtcSession: MockRTCSession;
|
||||||
room: MockRoom;
|
room: MockRoom;
|
||||||
}) {
|
}): ReactNode {
|
||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<TestReactionsWrapper rtcSession={rtcSession}>
|
<TestReactionsWrapper rtcSession={rtcSession}>
|
||||||
<ReactionToggleButton
|
<ReactionToggleButton
|
||||||
rtcSession={rtcSession as unknown as MatrixRTCSession}
|
rtcSession={rtcSession as unknown as MatrixRTCSession}
|
||||||
client={room.client}
|
client={room.client}
|
||||||
></ReactionToggleButton>
|
/>
|
||||||
</TestReactionsWrapper>
|
</TestReactionsWrapper>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Can open menu", async () => {
|
test("Can open menu", () => {
|
||||||
const room = new MockRoom(memberUserIdAlice);
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
const rtcSession = new MockRTCSession(room, membership);
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
const { getByRole, container } = render(
|
const { getByRole, container } = render(
|
||||||
@@ -47,7 +56,7 @@ test("Can open menu", async () => {
|
|||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Can close menu", async () => {
|
test("Can close menu", () => {
|
||||||
const room = new MockRoom(memberUserIdAlice);
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
const rtcSession = new MockRTCSession(room, membership);
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
const { getByRole, container } = render(
|
const { getByRole, container } = render(
|
||||||
@@ -60,7 +69,7 @@ test("Can close menu", async () => {
|
|||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Can raise hand", async () => {
|
test("Can raise hand", () => {
|
||||||
const room = new MockRoom(memberUserIdAlice);
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
const rtcSession = new MockRTCSession(room, membership);
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
const { getByRole, getByText, container } = render(
|
const { getByRole, getByText, container } = render(
|
||||||
@@ -88,7 +97,7 @@ test("Can raise hand", async () => {
|
|||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Can can lower hand", async () => {
|
test("Can can lower hand", () => {
|
||||||
const room = new MockRoom(memberUserIdAlice);
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
const rtcSession = new MockRTCSession(room, membership);
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
const { getByRole, getByText, container } = render(
|
const { getByRole, getByText, container } = render(
|
||||||
@@ -105,7 +114,7 @@ test("Can can lower hand", async () => {
|
|||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Can react with emoji", async () => {
|
test("Can react with emoji", () => {
|
||||||
const room = new MockRoom(memberUserIdAlice);
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
const rtcSession = new MockRTCSession(room, membership);
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
@@ -172,7 +181,47 @@ test("Can search for and send emoji", async () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Can close search", async () => {
|
test("Can search for and send emoji with the keyboard", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
|
const { getByText, getByRole, getByPlaceholderText, container } = render(
|
||||||
|
<TestComponent rtcSession={rtcSession} room={room} />,
|
||||||
|
);
|
||||||
|
act(() => {
|
||||||
|
getByRole("button").click();
|
||||||
|
});
|
||||||
|
act(() => {
|
||||||
|
getByRole("button", {
|
||||||
|
name: "Search",
|
||||||
|
}).click();
|
||||||
|
});
|
||||||
|
const searchField = getByPlaceholderText("Search reactions…");
|
||||||
|
await act(async () => {
|
||||||
|
searchField.focus();
|
||||||
|
await user.keyboard("crickets");
|
||||||
|
});
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
act(() => {
|
||||||
|
fireEvent.keyDown(searchField, { key: "Enter" });
|
||||||
|
});
|
||||||
|
expect(room.testSentEvents).toEqual([
|
||||||
|
[
|
||||||
|
undefined,
|
||||||
|
ElementCallReactionEventType,
|
||||||
|
{
|
||||||
|
"m.relates_to": {
|
||||||
|
event_id: memberEventAlice,
|
||||||
|
rel_type: "m.reference",
|
||||||
|
},
|
||||||
|
name: "crickets",
|
||||||
|
emoji: "🦗",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Can close search", () => {
|
||||||
const room = new MockRoom(memberUserIdAlice);
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
const rtcSession = new MockRTCSession(room, membership);
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
const { getByRole, container } = render(
|
const { getByRole, container } = render(
|
||||||
@@ -193,3 +242,24 @@ test("Can close search", async () => {
|
|||||||
});
|
});
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Can close search with the escape key", () => {
|
||||||
|
const room = new MockRoom(memberUserIdAlice);
|
||||||
|
const rtcSession = new MockRTCSession(room, membership);
|
||||||
|
const { getByRole, container, getByPlaceholderText } = render(
|
||||||
|
<TestComponent rtcSession={rtcSession} room={room} />,
|
||||||
|
);
|
||||||
|
act(() => {
|
||||||
|
getByRole("button").click();
|
||||||
|
});
|
||||||
|
act(() => {
|
||||||
|
getByRole("button", {
|
||||||
|
name: "Search",
|
||||||
|
}).click();
|
||||||
|
});
|
||||||
|
const searchField = getByPlaceholderText("Search reactions…");
|
||||||
|
act(() => {
|
||||||
|
fireEvent.keyDown(searchField, { key: "Escape" });
|
||||||
|
});
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|||||||
@@ -21,8 +21,12 @@ import {
|
|||||||
ChangeEventHandler,
|
ChangeEventHandler,
|
||||||
ComponentPropsWithoutRef,
|
ComponentPropsWithoutRef,
|
||||||
FC,
|
FC,
|
||||||
|
FormEventHandler,
|
||||||
|
KeyboardEvent,
|
||||||
|
KeyboardEventHandler,
|
||||||
ReactNode,
|
ReactNode,
|
||||||
useCallback,
|
useCallback,
|
||||||
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
@@ -31,6 +35,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
|||||||
import { EventType, RelationType } from "matrix-js-sdk/src/matrix";
|
import { EventType, RelationType } from "matrix-js-sdk/src/matrix";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import { useReactions } from "../useReactions";
|
import { useReactions } from "../useReactions";
|
||||||
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
||||||
@@ -40,7 +45,6 @@ import {
|
|||||||
ReactionSet,
|
ReactionSet,
|
||||||
ElementCallReactionEventType,
|
ElementCallReactionEventType,
|
||||||
} from "../reactions";
|
} from "../reactions";
|
||||||
import classNames from "classnames";
|
|
||||||
|
|
||||||
interface InnerButtonProps extends ComponentPropsWithoutRef<"button"> {
|
interface InnerButtonProps extends ComponentPropsWithoutRef<"button"> {
|
||||||
raised: boolean;
|
raised: boolean;
|
||||||
@@ -64,12 +68,12 @@ const InnerButton: FC<InnerButtonProps> = ({ raised, ...props }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function ReactionPopupMenu({
|
export function ReactionPopupMenu({
|
||||||
sendRelation,
|
sendReaction,
|
||||||
toggleRaisedHand,
|
toggleRaisedHand,
|
||||||
isHandRaised,
|
isHandRaised,
|
||||||
canReact,
|
canReact,
|
||||||
}: {
|
}: {
|
||||||
sendRelation: (reaction: ReactionOption) => void;
|
sendReaction: (reaction: ReactionOption) => void;
|
||||||
toggleRaisedHand: () => void;
|
toggleRaisedHand: () => void;
|
||||||
isHandRaised: boolean;
|
isHandRaised: boolean;
|
||||||
canReact: boolean;
|
canReact: boolean;
|
||||||
@@ -94,6 +98,26 @@ export function ReactionPopupMenu({
|
|||||||
[searchText, isSearching],
|
[searchText, isSearching],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onSearchKeyDown = useCallback<KeyboardEventHandler<never>>(
|
||||||
|
(ev) => {
|
||||||
|
if (ev.key === "Enter") {
|
||||||
|
ev.preventDefault();
|
||||||
|
if (!canReact) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (filteredReactionSet.length !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendReaction(filteredReactionSet[0]);
|
||||||
|
setIsSearching(false);
|
||||||
|
} else if (ev.key === "Escape") {
|
||||||
|
ev.preventDefault();
|
||||||
|
setIsSearching(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[sendReaction, filteredReactionSet, canReact, setIsSearching],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.reactionPopupMenu}>
|
<div className={styles.reactionPopupMenu}>
|
||||||
<section className={styles.handRaiseSection}>
|
<section className={styles.handRaiseSection}>
|
||||||
@@ -114,15 +138,17 @@ export function ReactionPopupMenu({
|
|||||||
<section>
|
<section>
|
||||||
{isSearching ? (
|
{isSearching ? (
|
||||||
<>
|
<>
|
||||||
<Form.Root
|
<Form.Root className={styles.searchForm}>
|
||||||
className={styles.searchForm}
|
|
||||||
onSubmit={(e) => e.preventDefault()}
|
|
||||||
>
|
|
||||||
<Search
|
<Search
|
||||||
|
required
|
||||||
value={searchText}
|
value={searchText}
|
||||||
name="reactionSearch"
|
name="reactionSearch"
|
||||||
placeholder="Search reactions…"
|
placeholder="Search reactions…"
|
||||||
onChange={onSearch}
|
onChange={onSearch}
|
||||||
|
onKeyDown={onSearchKeyDown}
|
||||||
|
// This is a reasonable use of autofocus, we are focusing when
|
||||||
|
// the search button is clicked (which matches the Element Web reaction picker)
|
||||||
|
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<CpdButton
|
<CpdButton
|
||||||
@@ -144,7 +170,7 @@ export function ReactionPopupMenu({
|
|||||||
kind="secondary"
|
kind="secondary"
|
||||||
className={styles.reactionButton}
|
className={styles.reactionButton}
|
||||||
disabled={!canReact}
|
disabled={!canReact}
|
||||||
onClick={() => sendRelation(reaction)}
|
onClick={() => sendReaction(reaction)}
|
||||||
>
|
>
|
||||||
{reaction.emoji}
|
{reaction.emoji}
|
||||||
</CpdButton>
|
</CpdButton>
|
||||||
@@ -287,7 +313,7 @@ export function ReactionToggleButton({
|
|||||||
<ReactionPopupMenu
|
<ReactionPopupMenu
|
||||||
isHandRaised={isHandRaised}
|
isHandRaised={isHandRaised}
|
||||||
canReact={canReact}
|
canReact={canReact}
|
||||||
sendRelation={(reaction) => void sendRelation(reaction)}
|
sendReaction={(reaction) => void sendRelation(reaction)}
|
||||||
toggleRaisedHand={toggleRaisedHand}
|
toggleRaisedHand={toggleRaisedHand}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ exports[`Can close search 1`] = `
|
|||||||
<button
|
<button
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
aria-expanded="true"
|
aria-expanded="true"
|
||||||
aria-labelledby=":rba:"
|
aria-labelledby=":rfg:"
|
||||||
class="_button_i91xf_17 raisedButton _has-icon_i91xf_66 _icon-only_i91xf_59"
|
class="_button_i91xf_17 raisedButton _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||||
data-kind="primary"
|
data-kind="primary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -232,7 +232,7 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-label="Toggle hand raised"
|
aria-label="Toggle hand raised"
|
||||||
aria-labelledby=":rbg:"
|
aria-labelledby=":rfm:"
|
||||||
aria-pressed="false"
|
aria-pressed="false"
|
||||||
class="_button_i91xf_17 reactionButton"
|
class="_button_i91xf_17 reactionButton"
|
||||||
data-kind="secondary"
|
data-kind="secondary"
|
||||||
@@ -253,7 +253,7 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
aria-labelledby=":rd2:"
|
aria-labelledby=":rh8:"
|
||||||
class="_button_i91xf_17 reactionButton"
|
class="_button_i91xf_17 reactionButton"
|
||||||
data-kind="secondary"
|
data-kind="secondary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -268,7 +268,7 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
aria-labelledby=":rd7:"
|
aria-labelledby=":rhd:"
|
||||||
class="_button_i91xf_17 reactionButton"
|
class="_button_i91xf_17 reactionButton"
|
||||||
data-kind="secondary"
|
data-kind="secondary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -283,7 +283,7 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
aria-labelledby=":rdc:"
|
aria-labelledby=":rhi:"
|
||||||
class="_button_i91xf_17 reactionButton"
|
class="_button_i91xf_17 reactionButton"
|
||||||
data-kind="secondary"
|
data-kind="secondary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -298,7 +298,7 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
aria-labelledby=":rdh:"
|
aria-labelledby=":rhn:"
|
||||||
class="_button_i91xf_17 reactionButton"
|
class="_button_i91xf_17 reactionButton"
|
||||||
data-kind="secondary"
|
data-kind="secondary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -313,7 +313,7 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
aria-labelledby=":rdm:"
|
aria-labelledby=":rhs:"
|
||||||
class="_button_i91xf_17 reactionButton"
|
class="_button_i91xf_17 reactionButton"
|
||||||
data-kind="secondary"
|
data-kind="secondary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -328,7 +328,7 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
aria-labelledby=":rdr:"
|
aria-labelledby=":ri1:"
|
||||||
class="_button_i91xf_17 reactionButton"
|
class="_button_i91xf_17 reactionButton"
|
||||||
data-kind="secondary"
|
data-kind="secondary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -343,7 +343,178 @@ exports[`Can close search 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-label="Open reactions search"
|
aria-label="Open reactions search"
|
||||||
aria-labelledby=":re0:"
|
aria-labelledby=":ri6:"
|
||||||
|
class="_button_i91xf_17 _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||||
|
data-kind="tertiary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414l-3.244-3.244ZM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</menu>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Can close search with the escape key 1`] = `
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-expanded="true"
|
||||||
|
aria-labelledby=":rii:"
|
||||||
|
class="_button_i91xf_17 raisedButton _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||||
|
data-kind="primary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M11 3a1 1 0 1 1 2 0v8.5a.5.5 0 0 0 1 0V4a1 1 0 1 1 2 0v10.2l3.284-2.597a1.081 1.081 0 0 1 1.47 1.577c-.613.673-1.214 1.367-1.818 2.064-1.267 1.463-2.541 2.934-3.944 4.235A6 6 0 0 1 5 15V7a1 1 0 0 1 2 0v5.5a.5.5 0 0 0 1 0V4a1 1 0 0 1 2 0v7.5a.5.5 0 0 0 1 0V3Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="reactionPopupMenu"
|
||||||
|
>
|
||||||
|
<section
|
||||||
|
class="handRaiseSection"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="Toggle hand raised"
|
||||||
|
aria-labelledby=":rio:"
|
||||||
|
aria-pressed="false"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
🖐️
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
<div
|
||||||
|
class="verticalSeperator"
|
||||||
|
/>
|
||||||
|
<section>
|
||||||
|
<menu>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-labelledby=":rka:"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
👍
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-labelledby=":rkf:"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
🎉
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-labelledby=":rkk:"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
👏
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-labelledby=":rkp:"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
🐶
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-labelledby=":rku:"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
🐱
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-labelledby=":rl3:"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
💡
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="Open reactions search"
|
||||||
|
aria-labelledby=":rl8:"
|
||||||
class="_button_i91xf_17 _has-icon_i91xf_66 _icon-only_i91xf_59"
|
class="_button_i91xf_17 _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||||
data-kind="tertiary"
|
data-kind="tertiary"
|
||||||
data-size="lg"
|
data-size="lg"
|
||||||
@@ -784,6 +955,7 @@ exports[`Can search for and send emoji 1`] = `
|
|||||||
id=":ra4:"
|
id=":ra4:"
|
||||||
name="reactionSearch"
|
name="reactionSearch"
|
||||||
placeholder="Search reactions…"
|
placeholder="Search reactions…"
|
||||||
|
required=""
|
||||||
type="search"
|
type="search"
|
||||||
value="crickets"
|
value="crickets"
|
||||||
/>
|
/>
|
||||||
@@ -837,3 +1009,130 @@ exports[`Can search for and send emoji 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`Can search for and send emoji with the keyboard 1`] = `
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-expanded="true"
|
||||||
|
aria-labelledby=":rba:"
|
||||||
|
class="_button_i91xf_17 raisedButton _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||||
|
data-kind="primary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="currentColor"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M11 3a1 1 0 1 1 2 0v8.5a.5.5 0 0 0 1 0V4a1 1 0 1 1 2 0v10.2l3.284-2.597a1.081 1.081 0 0 1 1.47 1.577c-.613.673-1.214 1.367-1.818 2.064-1.267 1.463-2.541 2.934-3.944 4.235A6 6 0 0 1 5 15V7a1 1 0 0 1 2 0v5.5a.5.5 0 0 0 1 0V4a1 1 0 0 1 2 0v7.5a.5.5 0 0 0 1 0V3Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="reactionPopupMenu"
|
||||||
|
>
|
||||||
|
<section
|
||||||
|
class="handRaiseSection"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="Toggle hand raised"
|
||||||
|
aria-labelledby=":rbg:"
|
||||||
|
aria-pressed="false"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
🖐️
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
<div
|
||||||
|
class="verticalSeperator"
|
||||||
|
/>
|
||||||
|
<section>
|
||||||
|
<form
|
||||||
|
class="_root_dgy0u_24 searchForm"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="_label_dgy0u_67 _field_dgy0u_34 _search_qztja_17"
|
||||||
|
for=":rd0:"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="_icon_qztja_46"
|
||||||
|
fill="currentColor"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414l-3.244-3.244ZM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<input
|
||||||
|
class="_input_qztja_61"
|
||||||
|
id=":rd0:"
|
||||||
|
name="reactionSearch"
|
||||||
|
placeholder="Search reactions…"
|
||||||
|
required=""
|
||||||
|
type="search"
|
||||||
|
value="crickets"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
aria-label="close search"
|
||||||
|
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="sm"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="currentColor"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="20"
|
||||||
|
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>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<div
|
||||||
|
class="_separator_144s5_17"
|
||||||
|
data-kind="primary"
|
||||||
|
data-orientation="horizontal"
|
||||||
|
role="separator"
|
||||||
|
/>
|
||||||
|
<menu>
|
||||||
|
<li
|
||||||
|
class="reactionPopupMenuItem"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-labelledby=":rdc:"
|
||||||
|
class="_button_i91xf_17 reactionButton"
|
||||||
|
data-kind="secondary"
|
||||||
|
data-size="lg"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
🦗
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</menu>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|||||||
Reference in New Issue
Block a user