diff --git a/packages/shared-components/src/menus/UserMenu/__snapshots__/UserMenu.test.tsx.snap b/packages/shared-components/src/menus/UserMenu/__snapshots__/UserMenu.test.tsx.snap
index 7c08d70dff..eca6f19cc5 100644
--- a/packages/shared-components/src/menus/UserMenu/__snapshots__/UserMenu.test.tsx.snap
+++ b/packages/shared-components/src/menus/UserMenu/__snapshots__/UserMenu.test.tsx.snap
@@ -345,7 +345,14 @@ exports[`UserMenu > renders a menu without an avatar 1`] = `
role="option"
tabindex="0"
>
- 💬 In a meeting
+
+ 💬
+
+
+ In a meeting
+
renders a menu without an avatar 1`] = `
role="option"
tabindex="0"
>
- 💡 Focus Time
+
+ 💡
+
+
+ Focus Time
+
renders a menu without an avatar 1`] = `
role="option"
tabindex="0"
>
- 🚙 On the road
+
+ 🚙
+
+
+ On the road
+
renders a menu without an avatar 1`] = `
role="option"
tabindex="0"
>
- ☕️ Be right back
+
+ ☕️
+
+
+ Be right back
+
renders a menu without an avatar 1`] = `
role="option"
tabindex="0"
>
- 🌴 Away
+
+ 🌴
+
+
+ Away
+
renders a menu without an avatar 1`] = `
role="option"
tabindex="0"
>
- ✍️ Custom…
+
+ ✍️
+
+
+ Custom…
+
@@ -779,7 +821,14 @@ exports[`UserMenu > renders an open menu 1`] = `
role="option"
tabindex="0"
>
- 💬 In a meeting
+
+ 💬
+
+
+ In a meeting
+
renders an open menu 1`] = `
role="option"
tabindex="0"
>
- 💡 Focus Time
+
+ 💡
+
+
+ Focus Time
+
renders an open menu 1`] = `
role="option"
tabindex="0"
>
- 🚙 On the road
+
+ 🚙
+
+
+ On the road
+
renders an open menu 1`] = `
role="option"
tabindex="0"
>
- ☕️ Be right back
+
+ ☕️
+
+
+ Be right back
+
renders an open menu 1`] = `
role="option"
tabindex="0"
>
- 🌴 Away
+
+ 🌴
+
+
+ Away
+
renders an open menu 1`] = `
role="option"
tabindex="0"
>
- ✍️ Custom…
+
+ ✍️
+
+
+ Custom…
+
diff --git a/packages/shared-components/src/status/SetStatusView.module.css b/packages/shared-components/src/status/SetStatusView.module.css
index c7342482b4..7c830a404c 100644
--- a/packages/shared-components/src/status/SetStatusView.module.css
+++ b/packages/shared-components/src/status/SetStatusView.module.css
@@ -30,3 +30,7 @@ Please see LICENSE files in the repository root for full details.
font-weight: var(--cpd-font-weight-medium);
font-size: var(--cpd-font-size-body-md);
}
+
+.dropdownEmoji {
+ margin-right: var(--cpd-space-1-5x);
+}
diff --git a/packages/shared-components/src/status/SetStatusView.test.tsx b/packages/shared-components/src/status/SetStatusView.test.tsx
index 734a2df830..ef98343b36 100644
--- a/packages/shared-components/src/status/SetStatusView.test.tsx
+++ b/packages/shared-components/src/status/SetStatusView.test.tsx
@@ -24,7 +24,7 @@ class SetStatusViewModel extends MockViewModel implements
*/
async function openCustomEditor(): Promise {
await userEvent.click(screen.getByRole("combobox"));
- await userEvent.click(screen.getByRole("option", { name: "✍️ Custom…" }));
+ await userEvent.click(screen.getByRole("option", { name: "✍️Custom…" }));
}
describe("SetStatusView", () => {
diff --git a/packages/shared-components/src/status/SetStatusView.tsx b/packages/shared-components/src/status/SetStatusView.tsx
index 43e690bada..d87b84dc09 100644
--- a/packages/shared-components/src/status/SetStatusView.tsx
+++ b/packages/shared-components/src/status/SetStatusView.tsx
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import React, { type JSX, useState } from "react";
+import React, { type JSX, useState, useCallback } from "react";
import { Dropdown, type DropdownTriggerProps, Link, Text } from "@vector-im/compound-web";
import { ReactionIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
@@ -15,16 +15,17 @@ import { StatusPillView } from "./StatusPillView";
import { CustomStatusView } from "./CustomStatusView";
import styles from "./SetStatusView.module.css";
-const PRESET_STATUSES = [
- { emoji: "💬", textKey: _td("status|set_status|in_a_meeting") },
- { emoji: "💡", textKey: _td("status|set_status|focus_time") },
- { emoji: "🚙", textKey: _td("status|set_status|on_the_road") },
- { emoji: "☕️", textKey: _td("status|set_status|be_right_back") },
- { emoji: "🌴", textKey: _td("status|set_status|away") },
-];
-
-// Sentinel value used to distinguish the "Custom…" dropdown entry from a preset.
-const CUSTOM_STATUS_VALUE = "custom";
+const STATUSES = {
+ in_a_meeting: { emoji: "💬", textKey: _td("status|set_status|in_a_meeting") },
+ focus_time: { emoji: "💡", textKey: _td("status|set_status|focus_time") },
+ on_the_road: { emoji: "🚙", textKey: _td("status|set_status|on_the_road") },
+ be_right_back: { emoji: "☕️", textKey: _td("status|set_status|be_right_back") },
+ away: { emoji: "🌴", textKey: _td("status|set_status|away") },
+ custom: { emoji: "✍️", textKey: _td("status|set_status|custom") },
+};
+type StatusValue = keyof typeof STATUSES;
+// No need to keep recompyuting this, it won't change
+const STATUS_KEYS = Object.keys(STATUSES) as StatusValue[];
export interface SetStatusViewSnapshot {
/**
@@ -58,10 +59,25 @@ export type SetStatusViewProps = {
vm: SetStatusViewModel;
};
+function StatusOption({ value }: { value: StatusValue }): React.ReactNode {
+ return (
+ <>
+ {STATUSES[value].emoji}
+ {_t(STATUSES[value].textKey)}
+ >
+ );
+}
+
export function SetStatusView({ vm }: SetStatusViewProps): JSX.Element {
const { userStatus } = useViewModel(vm);
const [customMode, setCustomMode] = useState(false);
+ const renderItem = useCallback((value: StatusValue | null): React.ReactNode => {
+ if (value === null) return null;
+
+ return ;
+ }, []);
+
if (userStatus) {
return ;
}
@@ -97,13 +113,13 @@ export function SetStatusView({ vm }: SetStatusViewProps): JSX.Element {
return trigger;
};
- const onValueChange = (value: string): void => {
- if (value === CUSTOM_STATUS_VALUE) {
+ const onValueChange = (value: StatusValue): void => {
+ if (value === "custom") {
setCustomMode(true);
return;
}
- const status = PRESET_STATUSES.find((s) => s.textKey === value);
+ const status = STATUSES[value];
if (!status) {
return;
@@ -115,20 +131,15 @@ export function SetStatusView({ vm }: SetStatusViewProps): JSX.Element {
});
};
- const dropdownValues: Array<[string, string]> = [
- ...PRESET_STATUSES.map((s): [string, string] => [s.textKey, `${s.emoji} ${_t(s.textKey)}`]),
- [CUSTOM_STATUS_VALUE, `✍️ ${_t("status|set_status|custom")}`],
- ];
-
return vm.onSetStatusClick ? (
renderTrigger({ onClick: vm.onSetStatusClick })
) : (
-
+ values={STATUS_KEYS}
label={null}
- placeholder={null}
trigger={renderTrigger}
onValueChange={onValueChange}
+ renderItem={renderItem}
/>
);
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1458ba23f5..c1d8f0b4e1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -222,8 +222,8 @@ catalogs:
specifier: 10.2.1
version: 10.2.1
'@vector-im/compound-web':
- specifier: 9.9.0
- version: 9.9.0
+ specifier: 10.0.0
+ version: 10.0.0
'@vitejs/plugin-react':
specifier: 6.0.5
version: 6.0.5
@@ -557,7 +557,7 @@ importers:
version: 10.2.1(@types/react@19.2.18)(react@19.2.8)
'@vector-im/compound-web':
specifier: 'catalog:'
- version: 9.9.0(@fontsource/inconsolata@5.2.8)(@fontsource/inter@5.3.0)(@types/react-dom@19.2.3)(@types/react@19.2.18)(@vector-im/compound-design-tokens@10.2.1)(react-dom@19.2.8)(react@19.2.8)
+ version: 10.0.0(@fontsource/inconsolata@5.2.8)(@fontsource/inter@5.3.0)(@types/react-dom@19.2.3)(@types/react@19.2.18)(@vector-im/compound-design-tokens@10.2.1)(react-dom@19.2.8)(react@19.2.8)
'@vector-im/matrix-wysiwyg':
specifier: 2.40.0
version: 2.40.0(patch_hash=7bdf6150f2905bc2f055a6bcaa7b9d78fa7ffde82e800bcc454ac7b0096bd65e)(react@19.2.8)
@@ -1501,7 +1501,7 @@ importers:
version: typescript@7.0.2
'@vector-im/compound-web':
specifier: 'catalog:'
- version: 9.9.0(@fontsource/inconsolata@5.2.8)(@fontsource/inter@5.3.0)(@types/react-dom@19.2.3)(@types/react@19.2.18)(@vector-im/compound-design-tokens@10.2.1)(react-dom@19.2.8)(react@19.2.8)
+ version: 10.0.0(@fontsource/inconsolata@5.2.8)(@fontsource/inter@5.3.0)(@types/react-dom@19.2.3)(@types/react@19.2.18)(@vector-im/compound-design-tokens@10.2.1)(react-dom@19.2.8)(react@19.2.8)
'@vitejs/plugin-react':
specifier: 'catalog:'
version: 6.0.5(vite@8.2.0)
@@ -6572,6 +6572,18 @@ packages:
react:
optional: true
+ '@vector-im/compound-web@10.0.0':
+ resolution: {integrity: sha512-Gdxi+MjOTds1QwXw1bFy6NQnTgynNeSCmmOS7Q9c7pogaZQlpEYaEu6mPXww6T6TwBRgK7MNDXvF3k5C8h653Q==}
+ peerDependencies:
+ '@fontsource/inconsolata': ^5
+ '@fontsource/inter': ^5
+ '@types/react': ^19.2.10
+ '@vector-im/compound-design-tokens': '>=1.6.1 <11.0.0'
+ react: ^18 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@vector-im/compound-web@9.9.0':
resolution: {integrity: sha512-GjAEhzB/mt9MA7Y1ySe6/AlW26vodDu4hvTi1ThB5rTrt4KAiHMpvk+T56KV5Lwo0VvBxAyHMtm/IY5tkyH12A==}
peerDependencies:
@@ -19112,6 +19124,28 @@ snapshots:
'@types/react': 19.2.18
react: 19.2.8
+ '@vector-im/compound-web@10.0.0(@fontsource/inconsolata@5.2.8)(@fontsource/inter@5.3.0)(@types/react-dom@19.2.3)(@types/react@19.2.18)(@vector-im/compound-design-tokens@10.2.1)(react-dom@19.2.8)(react@19.2.8)':
+ dependencies:
+ '@floating-ui/react': 0.27.17(react-dom@19.2.8)(react@19.2.8)
+ '@floating-ui/react-dom': 2.1.9(react-dom@19.2.8)(react@19.2.8)
+ '@fontsource/inconsolata': 5.2.8
+ '@fontsource/inter': 5.3.0
+ '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.3)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8)
+ '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8)
+ '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.3)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8)
+ '@radix-ui/react-progress': 1.1.8(@types/react-dom@19.2.3)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8)
+ '@radix-ui/react-separator': 1.1.8(@types/react-dom@19.2.3)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8)
+ '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.8)
+ '@vector-im/compound-design-tokens': 10.2.1(@types/react@19.2.18)(react@19.2.8)
+ classnames: 2.5.1
+ react: 19.2.8
+ vaul: 1.1.2(@types/react-dom@19.2.3)(@types/react@19.2.18)(react-dom@19.2.8)(react@19.2.8)
+ optionalDependencies:
+ '@types/react': 19.2.18
+ transitivePeerDependencies:
+ - '@types/react-dom'
+ - react-dom
+
'@vector-im/compound-web@9.9.0(@fontsource/inconsolata@5.2.8)(@fontsource/inter@5.3.0)(@types/react-dom@19.2.3)(@types/react@19.2.18)(@vector-im/compound-design-tokens@10.2.1)(react-dom@19.2.8)(react@19.2.8)':
dependencies:
'@floating-ui/react': 0.27.17(react-dom@19.2.8)(react@19.2.8)
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 4acfe73b56..3d4b5bb72c 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -27,7 +27,7 @@ catalog:
"playwright-core": 1.61.1
# Compound
"@vector-im/compound-design-tokens": 10.2.1
- "@vector-im/compound-web": 9.9.0
+ "@vector-im/compound-web": 10.0.0
# i18n
matrix-web-i18n: 3.6.0
# emojibase