Commit Graph
16 Commits
Author SHA1 Message Date
fkwp 0802649375 Show the focus ring for the keyboard alone, and fix the radio styling
- Show the focus ring only when the keyboard moved the focus. Radix focuses
  whatever the pointer is over, so the browser cannot answer that question
  here: Chromium treats every focus after a key press as keyboard-driven,
  Firefox treats no programmatic focus as keyboard-driven. The menu records
  which modality arrived, watched at the document while it is open, since the
  first arrow key lands on the menu itself rather than on anything we render.
- Suppress the browser's own ring on menu items, so there is one answer to
  that question rather than two.
- Drop readOnly from the device radios. Compound paints a read-only control
  muted, and that rule comes after the checked rule, so it overrode the accent
  fill marking the selection and the menu stopped matching settings.
- Make the decorative radio inert rather than aria-hidden. A negative tabindex
  inside an interactive control stays reachable to assistive technology even
  when hidden, which axe rejects.
- Give each section a labelled group and mark its heading decorative. A menu
  may contain only items, separators and groups, and the headings were direct
  children of it. The list wrappers are role="none" for the same reason.
- Run axe over the open menu, which is what found both of the above.

Spec: FEATURES_SPEC/2026-09_Quick_Audio_Menu.md — AC23, AC24, AC25
2026-09-16 17:44:55 +02:00
fkwp 7f3b98ed6a Size the device menu against the call, and cover its criteria
- Bound the scrolling device list by the measured height of the call area.
  It was capped with a viewport unit and a Radix variable, both of which
  measure the window: as a component in a corner of a host's page, the menu
  would have been sized against the whole page. The menu is portalled outside
  the root, so no container query reaches it and it has to be measured.
- Leave a single divider between the two lists, as the design has. Compound
  underlines every menu heading, so the headings drop theirs, and the line
  closing the microphone section goes: the section wrapper already bounds the
  meter's stickiness without one.
- Cover device persistence, hot-plug, fallback when the device in use is
  removed, fallback to a default when a remembered device is gone, numbered
  labels before permission, "Default" listed as its own entry, one device kind
  not disturbing another, and camera parity. Their acceptance criteria named
  check commands for tests that did not exist, which makes the criteria
  unenforceable and blocks the next drift check.

Spec: FEATURES_SPEC/2026-09_Quick_Audio_Menu.md — AC3, AC4, AC5, AC8, AC9,
AC10, AC11, AC19, AC20
2026-09-16 16:23:02 +02:00
fkwp 9a68de193f Show a live microphone level in the audio menu
- Draw the input level beneath the microphone list as 32 discrete segments,
  so the level reads by count and not by hue alone.
- Expose it through role="meter" with aria-valuenow and aria-valuetext, so a
  screen reader announces it.
- Give denied permission and no input device their own message and next
  action, rather than a flat meter that reads as silence.
- Read the level only while the menu is open, so nothing holds a second
  capture of the microphone for the length of a call.
- Read the device the picker has selected, so the meter re-points as soon as
  the selection changes.
- Ignore anything below a noise floor: a quiet room is never digitally
  silent, and its hiss otherwise lights the first segments permanently, which
  reads as "it can hear me" when nobody is speaking.
- Quantise loudness with a square root above that floor: amplitude puts
  ordinary speech near the bottom of the range, where a linear meter barely
  moves.
- Withhold the output select callback where the platform cannot route audio
  to a chosen device, which is what renders the speaker section disabled.
  Safari and most Firefox builds land here.
- Track the in-flight device by kind as well as id: Chrome names both an
  input and an output "default", so the spinner appeared on the wrong row.
- Disable every device in the menu while a selection is settling, so a second
  request cannot overtake the first.

The meter opens its own short-lived capture rather than tapping the call's
audio track. That is what lets it follow the picker instantly, and it avoids
the pre-join track, which is deliberately frozen to the device selected when
the screen mounted. The cost is a second capture of the same device while the
menu is open. See the spec's notes sidecar.

Spec: FEATURES_SPEC/2026-09_Quick_Audio_Menu.md — AC1, AC6, AC7, AC13, AC14,
AC15, AC17, AC18, AC21, AC22
2026-09-16 14:52:59 +02:00
fkwp 664fac104f Use radio controls to mark the selected device in the quick menu
- Mark the selection with a radio control instead of a trailing check icon
  beside a device glyph, matching the design and the settings modal, so both
  device pickers read the same way.
- Take the visual from Compound's RadioInput rather than restyling a span of
  our own. RadioControl is wrapped in a Radix form control and needs a Form
  ancestor, which a dropdown menu has no business providing; RadioInput does
  not.
- Keep rows as menuitemradio with aria-checked, rendered through
  MenuItem as="div" so an input is never nested inside a button.
- Render the radio aria-hidden and not focusable: Radix owns focus inside the
  menu, and aria-checked carries the state.
- Leave the activating spinner unchanged.
- Keep every scope.behavior call inside the function that owns the scope,
  which no-observablescope-leak requires.
- Cover the speaker section, an output that cannot be chosen, and a lone
  device shown disabled, with unit tests and stories for each.

Spec: FEATURES_SPEC/2026-09_Quick_Audio_Menu.md — AC1, AC7
2026-09-16 14:02:01 +02:00
Robin 11fadebb87 Fix test failures due to scoped class names 2026-07-08 17:06:25 +02:00
Valere acc5a440c7 review: remove unneeded early return 2026-06-05 12:35:21 +02:00
Valere 4606373e5b feat(mute): add syncing state and disable toggle during async mute 2026-06-04 18:55:31 +02:00
Robin 5fed562db2 Request full device names when device switchers are open 2026-06-02 10:36:57 +02:00
Robin 164765cd27 Show the right fallback labels in device switcher menus 2026-06-02 10:15:40 +02:00
Timo K dc52573ce2 fix backgroundBlurToggleClick -> videoBlurToggleClick 2026-05-20 17:03:45 +02:00
Timo K a494b64055 Update MediaMuteAndSwitchButton.test.tsx 2026-05-18 21:00:55 +02:00
Timo K 68a487c9de translation fixes 2026-05-18 19:17:43 +02:00
Timo K d5bebcc3a5 refactor video blur toggle 2026-05-18 18:11:32 +02:00
Timo K e10bc6c7cf fix unit tests 2026-05-13 13:35:12 +02:00
Timo K 07e7090cc7 fix unit tests 2026-05-12 16:50:45 +02:00
Timo f4ff790d2c Add MediaMuteAndSwitchButton component (storybook only) (#3938)
* add MeidaMuteAndSwitchButton

* User button in footer

* Add tests

* update styling (dark bg on menu open + chevron white + chevron up)

* fix tests

* add storybook to CI

only add storybook with storybook label

test names

another env name test

TestName

new default name

remove label condition

Update pr-deploy.yaml

* Update pr-deploy.yaml

* add toggle example to default component

* hook up footer select actions

* fix video audio button (swapped) and lable in story
2026-05-11 11:50:33 +02:00