Add user status to autocomplete suggestion (#34241)
* Add user status to autocomplete suggestion * Add test for PillCompletion titleIcon * Convert to vitest * Add test for UserStatusIcon * Switch the user status icon view to be a view model based component * Screenshots * Add .catch * Add test for UserProvider
This commit is contained in:
BIN
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -95,5 +95,6 @@ export * from "./core/utils/linkify";
|
||||
export type * from "./core/userStatus.ts";
|
||||
export * from "./status/SetStatusView";
|
||||
export * from "./status/StatusTextView";
|
||||
export * from "./status/UserStatusIconView";
|
||||
// MVVM
|
||||
export * from "./core/viewmodel";
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type Meta, type StoryObj } from "@storybook/react-vite";
|
||||
|
||||
import { UserStatusIconView, type UserStatusIconViewModel } from "./UserStatusIconView";
|
||||
import { MockViewModel } from "../core/viewmodel/MockViewModel";
|
||||
|
||||
const meta = {
|
||||
title: "Status/UserStatusIconView",
|
||||
component: UserStatusIconView,
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
vm: new MockViewModel({ status: { emoji: "🐎", text: "on a horse" } }) as UserStatusIconViewModel,
|
||||
},
|
||||
} satisfies Meta<typeof UserStatusIconView>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const NoStatus: Story = {
|
||||
args: {
|
||||
vm: new MockViewModel({ status: undefined }) as UserStatusIconViewModel,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { composeStories } from "@storybook/react-vite";
|
||||
import React from "react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { render, screen, waitFor } from "@test-utils";
|
||||
|
||||
import * as stories from "./UserStatusIconView.stories";
|
||||
|
||||
const { Default, NoStatus } = composeStories(stories);
|
||||
|
||||
describe("UserStatusIconView", () => {
|
||||
it("renders nothing when the user has no status", () => {
|
||||
const { container } = render(<NoStatus />);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it("renders the status emoji", () => {
|
||||
render(<Default />);
|
||||
expect(screen.getByText("🐎")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows the status text in a tooltip on hover", async () => {
|
||||
render(<Default />);
|
||||
|
||||
await userEvent.hover(screen.getByText("🐎"));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("tooltip")).toHaveTextContent("on a horse");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX } from "react";
|
||||
import { Text, Tooltip } from "@vector-im/compound-web";
|
||||
|
||||
import { type ViewModel, useViewModel } from "../core/viewmodel";
|
||||
import { type UserStatus } from "..";
|
||||
|
||||
/**
|
||||
* Snapshot for the UserStatusIconView.
|
||||
*/
|
||||
export interface UserStatusIconViewSnapshot {
|
||||
/**
|
||||
* The user's status, or undefined if not available.
|
||||
*/
|
||||
status?: UserStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* The view model for UserStatusIconView.
|
||||
*/
|
||||
export type UserStatusIconViewModel = ViewModel<UserStatusIconViewSnapshot>;
|
||||
|
||||
interface UserStatusIconViewProps {
|
||||
/**
|
||||
* The view model for the user status icon.
|
||||
*/
|
||||
vm: UserStatusIconViewModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the MSC4426 status emoji for a user, e.g. after their display name
|
||||
* in the user mention autocomplete. Renders nothing if the user has no status.
|
||||
*/
|
||||
export function UserStatusIconView({ vm }: Readonly<UserStatusIconViewProps>): JSX.Element | null {
|
||||
const { status } = useViewModel(vm);
|
||||
if (!status) return null;
|
||||
return (
|
||||
<Tooltip description={status.text}>
|
||||
<Text as="span">{status.emoji}</Text>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user