From 7b877e337e0bbe16bd9b638db532426b5a77f661 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 8 Oct 2026 22:38:58 -0300 Subject: [PATCH 1/5] refactor(ui-conference): Fuse device toggles with fuselage SplitButton The microphone and camera controls fused each device menu with its toggle through local CSS that zeroed the button radii and faded the menu trigger. They now use SplitButton, with the device menu as its ghost trigger and the group turning danger while the device is off. --- .../src/call/AudioDevicePicker.tsx | 1 + .../ui-conference/src/call/CallControls.tsx | 80 +- .../ui-conference/src/call/CameraPicker.tsx | 11 +- .../__snapshots__/callStories.spec.tsx.snap | 1106 ++++++++--------- 4 files changed, 550 insertions(+), 648 deletions(-) diff --git a/packages/ui-conference/src/call/AudioDevicePicker.tsx b/packages/ui-conference/src/call/AudioDevicePicker.tsx index cb450bcf2038f..ded4709d128fb 100644 --- a/packages/ui-conference/src/call/AudioDevicePicker.tsx +++ b/packages/ui-conference/src/call/AudioDevicePicker.tsx @@ -23,6 +23,7 @@ const AudioDevicePicker = () => { beforeOpen={() => revealDeviceLabels(['audioinput', 'audiooutput'], devices)} button={ } diff --git a/packages/ui-conference/src/call/CallControls.tsx b/packages/ui-conference/src/call/CallControls.tsx index 13b05244cac80..bdd93b6f353bf 100644 --- a/packages/ui-conference/src/call/CallControls.tsx +++ b/packages/ui-conference/src/call/CallControls.tsx @@ -1,5 +1,5 @@ import { css } from '@rocket.chat/css-in-js'; -import { Box, ButtonGroup, Palette, RadioButton, borderRadius } from '@rocket.chat/fuselage'; +import { Box, ButtonGroup, Palette, RadioButton, SplitButton, borderRadius } from '@rocket.chat/fuselage'; import type { Keys } from '@rocket.chat/icons'; import { GenericMenu } from '@rocket.chat/ui-client'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; @@ -125,22 +125,6 @@ const controlNoticesStyles = css` } `; -// A device toggle and its selector fused into one control, the selector first and a shade quieter. -const deviceControlStyles = css` - display: inline-flex; - align-items: stretch; - overflow: hidden; - border-radius: ${borderRadius('medium')}; - - & button { - border-radius: 0; - } - - & > *:first-child button { - opacity: 0.7; - } -`; - export type CallControlsProps = { layout: StageLayout; onLayoutChange: (layout: StageLayout) => void; @@ -197,41 +181,33 @@ const CallControls = ({ layout, onLayoutChange, onOpenDiagnostics }: CallControl return ( - - - - - - - - - - - - - - - - + + + + + + + + { choices={[videoQuality]} // A call joined with the camera off may not have the permission that names the cameras yet. beforeOpen={() => revealDeviceLabels(['videoinput'], devices)} - button={} + button={ + + } /> ); }; diff --git a/packages/ui-conference/src/call/__snapshots__/callStories.spec.tsx.snap b/packages/ui-conference/src/call/__snapshots__/callStories.spec.tsx.snap index 1ae533f92f582..85e2355af1b1a 100644 --- a/packages/ui-conference/src/call/__snapshots__/callStories.spec.tsx.snap +++ b/packages/ui-conference/src/call/__snapshots__/callStories.spec.tsx.snap @@ -13,7 +13,7 @@ exports[`call stories renders AudioDevicePicker MicrophoneOn without crashing 1` aria-expanded="false" aria-haspopup="true" aria-label="Device options" - class="rcx-box rcx-box--full rcx-button--large-square rcx-button--icon-secondary rcx-button--square rcx-button--icon rcx-button rcx-css-1wk08i8" + class="rcx-box rcx-box--full rcx-split-button__trigger rcx-button--large-square rcx-button--icon-secondary rcx-button--square rcx-button--icon rcx-button rcx-css-1wk08i8" id="react-aria-_r_0_" label="Device options" title="Device settings" @@ -60,7 +60,7 @@ exports[`call stories renders AudioDevicePicker Muted without crashing 1`] = ` aria-expanded="false" aria-haspopup="true" aria-label="Device options" - class="rcx-box rcx-box--full rcx-button--large-square rcx-button--icon-secondary-danger rcx-button--square rcx-button--icon rcx-button rcx-css-1wk08i8" + class="rcx-box rcx-box--full rcx-split-button__trigger rcx-button--large-square rcx-button--icon-secondary-danger rcx-button--square rcx-button--icon rcx-button rcx-css-1wk08i8" id="react-aria-_r_2_" label="Device options" title="Device settings" @@ -98,107 +98,95 @@ exports[`call stories renders CallBar Default without crashing 1`] = ` style="position: relative;" >
- -
+
+
+
+ + -
+  + +
- -
+ + -
+ ❴ + +
-
-
+
+
+
+ + -
+  + +
- -
+ + -
+ ❲ + +
- -
- +
+
- -
+ + -
+ ❴ + +
- -
+
+
+
+ + -
+  + +
- -
+ + -
+ ❴ + +
- -
+ + -
+  + +
- -
+ + -
+ ❴ + +
- -
+
+
+
+ + -
+  + +
- -
+ + -
+ ❴ + +
- -
+ + -
+  + +
- -
+ + -
+ ❴ + +
@@ -536,7 +536,7 @@ exports[`call stories renders CallControls Default without crashing 1`] = `
@@ -728,7 +728,7 @@ exports[`call stories renders CallControls HandRaised without crashing 1`] = `
@@ -905,7 +905,7 @@ exports[`call stories renders CallControls Muted without crashing 1`] = `
@@ -1097,7 +1097,7 @@ exports[`call stories renders CallControls OneOnOne without crashing 1`] = `
@@ -1274,7 +1274,7 @@ exports[`call stories renders CallControls SpeakingWhileMuted without crashing 1