diff --git a/src/components/MediaMuteAndSwitchButton.module.css b/src/components/MediaMuteAndSwitchButton.module.css index 91282cea4..a8b313b74 100644 --- a/src/components/MediaMuteAndSwitchButton.module.css +++ b/src/components/MediaMuteAndSwitchButton.module.css @@ -436,9 +436,12 @@ Please see LICENSE in the repository root for full details. * frame's corner, because a video paints on a layer of its own and would * otherwise draw over the outline the menu is framed with. * - * Sixteen by nine and never taller than its budget, cropped rather than - * letterboxed: a face cut at the edge reads as a self-view, a face in bars - * reads as a broken one. + * A fixed height rather than a ratio: sixteen by nine at the menu's narrowest, + * and wider as a long device name widens the menu, cropped rather than + * letterboxed — a face cut at the edge reads as a self-view, a face in bars + * reads as a broken one. Not aspect-ratio with a height cap: once the cap + * holds, Safari keeps the ratio by narrowing the box instead of the picture, + * and the preview stops short of the menu's right edge. */ .selfPreview { position: relative; @@ -450,8 +453,7 @@ Please see LICENSE in the repository root for full details. ); margin-inline: var(--cpd-border-width-1); margin-block-end: var(--cpd-space-2x); - aspect-ratio: 16 / 9; - max-block-size: 176px; + block-size: 176px; overflow: hidden; border-start-start-radius: calc( var(--cpd-space-3x) - var(--cpd-border-width-1) diff --git a/src/components/MediaMuteAndSwitchButton.stories.tsx b/src/components/MediaMuteAndSwitchButton.stories.tsx index 34350432b..a29deb3b1 100644 --- a/src/components/MediaMuteAndSwitchButton.stories.tsx +++ b/src/components/MediaMuteAndSwitchButton.stories.tsx @@ -1168,6 +1168,36 @@ export const BackgroundEffectsWithALongDeviceName: Story = { }, }; +/** + * A long device name widens the menu past the width at which the preview is + * sixteen by nine. The preview still spans it: Safari, given a ratio and a + * height cap, kept the ratio by narrowing the box and left a strip of menu at + * its right. Checked here in Chromium, which never did — no test tier here + * runs WebKit — so this holds the requirement, not the engine. + */ +export const BackgroundEffectsWithPreviewInAWideMenu: Story = { + args: { + ...BackgroundEffectsWithALongDeviceName.args, + selfPreview: , + }, + parameters: { callAreaHeight: 720 }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button", { name: "Camera" })); + await within(document.body).findByRole("menuitemradio", { name: "Blur" }); + + const menu = document.body.querySelector("[role='menu']")!; + const preview = menu.querySelector(`.${styles.selfPreview}`)!; + const frame = menu.getBoundingClientRect(); + const box = preview.getBoundingClientRect(); + // Wider than the preview's sixteen-by-nine width, or this proves nothing. + await expect(frame.width).toBeGreaterThan((176 * 16) / 9 + 8); + await expect(frame.right - box.right).toBeLessThanOrEqual(2); + await expect(box.left - frame.left).toBeLessThanOrEqual(2); + await expect(Math.round(box.height)).toBe(176); + }, +}; + /** * Backgrounds the user added are theirs to remove — except the one in force, * which is what they are wearing. diff --git a/src/components/MediaMuteAndSwitchButton.tsx b/src/components/MediaMuteAndSwitchButton.tsx index 12d8ec3c5..2cd6a9d5e 100644 --- a/src/components/MediaMuteAndSwitchButton.tsx +++ b/src/components/MediaMuteAndSwitchButton.tsx @@ -188,11 +188,11 @@ const MIN_LIST_HEIGHT = 160; /** * The most the self-preview may take, which is also what it costs the list. * - * Drawn at sixteen by nine across the full width of the menu, capped here so - * that a menu widened by a long device name cannot make it taller than its - * budget. The preview is paid for out of the list's share rather than on top - * of it, so the menu is never taller for having one: where the list could not - * keep its floor after paying, there is no preview at all. + * Its fixed height: sixteen by nine across the menu at its narrowest, and + * cropped wider as the menu widens, so it never costs more than this. The + * preview is paid for out of the list's share rather than on top of it, so the + * menu is never taller for having one: where the list could not keep its floor + * after paying, there is no preview at all. */ const PREVIEW_BLOCK = 176;