diff --git a/src/components/MediaMuteAndSwitchButton.module.css b/src/components/MediaMuteAndSwitchButton.module.css index de686d027..09a4e302a 100644 --- a/src/components/MediaMuteAndSwitchButton.module.css +++ b/src/components/MediaMuteAndSwitchButton.module.css @@ -136,22 +136,6 @@ Please see LICENSE in the repository root for full details. outline-offset: calc(-1 * var(--cpd-border-width-2)); } -/* A heading that is ruled off sits closer to its rule than the menu's own - spacing allows, which is set for a heading with nothing under it. */ -.menu .sectionHeadingRuled h3 { - padding-block-end: var(--cpd-space-1x); -} - -/* The rule under a section heading, drawn edge to edge. A separator insets - itself by default, which leaves it floating short of the menu's sides. - The menu also gives a separator room beneath it, for one dividing two - sections; under a heading that reads as the heading floating away from - what it names. */ -.menu .sectionRule { - margin-inline: 0; - margin-block-end: var(--cpd-space-3x); -} - /* * The Background effects grid. * @@ -183,11 +167,12 @@ Please see LICENSE in the repository root for full details. their left edge up with the "B" of the heading above them and with the radio buttons above that. Matching the surrounding boxes instead puts the tiles to the left of both, since a heading insets its own text. */ - /* The same distance to the menu's frame on every side. The rule above and - the menu's own bottom padding already supply part of that, so what is set - here is only the remainder: the sides carry it all, the top is topped up - over the rule's spacing, and the bottom is left to the menu. */ - padding: var(--cpd-space-1x) var(--cpd-space-4x) 0; + /* The sides carry the full inset to the menu's frame. Above, the grid is + the first control of its section, so it starts where a device row's + control starts under its own rule: the heading's spacing supplies most of + that, and this adds the same step a device row holds above its control. + Below, the menu's own padding is already the inset, so nothing is set. */ + padding: var(--cpd-space-2x) var(--cpd-space-4x) 0; } /* diff --git a/src/components/MediaMuteAndSwitchButton.stories.tsx b/src/components/MediaMuteAndSwitchButton.stories.tsx index 50f8c2e30..3e358c2fd 100644 --- a/src/components/MediaMuteAndSwitchButton.stories.tsx +++ b/src/components/MediaMuteAndSwitchButton.stories.tsx @@ -823,6 +823,40 @@ export const BackgroundEffects: Story = { const canvas = within(canvasElement); await userEvent.click(canvas.getByRole("button", { name: "Camera" })); + // The section is headed by its own rule, drawn edge to edge like the + // camera section's above it, and nothing divides the two besides. + const menu = document.body.querySelector("[role='menu']")!; + await expect( + document.body.querySelectorAll("[role='separator']"), + ).toHaveLength(0); + const headings = document.body.querySelectorAll( + `.${styles.sectionHeading}`, + ); + await expect(headings).toHaveLength(2); + const frame = menu.getBoundingClientRect(); + const rules = [...headings].map((h) => h.querySelector("h3")!); + for (const rule of rules) { + await expect( + Number.parseFloat(getComputedStyle(rule).borderBottomWidth), + ).toBeGreaterThan(0); + const box = rule.getBoundingClientRect(); + await expect(box.left - frame.left).toBeLessThanOrEqual(2); + await expect(frame.right - box.right).toBeLessThanOrEqual(2); + } + + // The grid is its section's first control, so it starts under its rule + // where the camera list's first control starts under that one. Stated as + // the two being level, because the design draws them level; measured off + // the mock they sit within a couple of pixels of each other. + const radio = document.body.querySelector("input[type='radio']")!; + const tile = document.body.querySelector(`.${styles.effectTile}`)!; + const under = (control: Element, rule: Element): number => + control.getBoundingClientRect().top - + rule.getBoundingClientRect().bottom; + await expect( + Math.abs(under(radio, rules[0]) - under(tile, rules[1])), + ).toBeLessThanOrEqual(1); + const blur = await within(document.body).findByRole("menuitemradio", { name: "Blur", }); diff --git a/src/components/MediaMuteAndSwitchButton.tsx b/src/components/MediaMuteAndSwitchButton.tsx index 4c0578456..25ada915d 100644 --- a/src/components/MediaMuteAndSwitchButton.tsx +++ b/src/components/MediaMuteAndSwitchButton.tsx @@ -721,21 +721,9 @@ export const MediaMuteAndSwitchButton: FC = ({ )}
-
+
- {/* The camera menu rules off under each heading. The microphone - menu still divides its two sections instead, which is the - design the audio menu was drawn to. */} - {iconsAndLabels === "video" && ( - - )} {/* The heading sits outside, so the meter can never ride up over it: sticky only holds while this block is in view. */}
@@ -762,16 +750,9 @@ export const MediaMuteAndSwitchButton: FC = ({ role="group" aria-label={t("settings.background_effects_header")} > -
+
-
{effectTiles()}