fix: custom category never highlighted in the emoji picker header

BY
1d ago
+223-8

Proposed changes (including videos or screenshots)

getCategoriesList splices the Custom category out of the list and pushes it to the end, so its divider is always the last entry in categoriesIndexes. The scroll handler worked out the active category by dereferencing the next entry to find where the current one ends:

const category = categoriesIndexes.find(
	(category, index) => category.index <= startIndex + 1 && categoriesIndexes[index + 1]?.index >= startIndex,
);

There is no next entry for the last one, so undefined >= startIndex is always false, find returns undefined, and the if (!category) return; below it skips setCurrentCategory. The category that is unconditionally placed last is the one this lookup can never reach.

BeforeAfter
Flags stays highlighted after clicking CustomCustom highlighted after clicking it

Reading the tablist directly on my test workspace, before the change:

symbols aria-selected=false
flags   aria-selected=true
rocket  aria-selected=false

Fixing only the off-by-one is not enough. createPickerEmojis emits a divider row for Custom whether or not the workspace has any custom emoji, so on a workspace with few or none the divider sits among the final rows and the list runs out of scroll before it can reach the top. On my workspace the list is 227 rows, the Custom divider is row 225, and clicking Custom leaves the rendered range at 217-225 with 32px of scroll to spare. No rule based on the first visible row can select it there.

So getCurrentCategory keeps the existing behaviour for every other category, matching the last divider above the top of the viewport, and treats the final category as current as soon as its divider is rendered. I checked the old and new lookups against each other across every scroll position: they agree everywhere except inside the last category, where the old one returned undefined and left the header unchanged.

Issue(s)

Closes #42133

Steps to test or reproduce

  1. Open the emoji picker from the message composer.
  2. Click the Custom category, the rocket icon at the end of the header.
  3. The list scrolls to the Custom divider and the rocket icon is highlighted.

Also worth checking that the rest of the header still tracks scrolling: click a category in the middle, then scroll by hand through a few sections and watch the highlight follow the section at the top of the list.

Further comments

Pulling the lookup out of the component makes it testable on its own, so helpers.spec.ts covers the top of the list, the middle categories, the divider boundary, the last category, and an empty list. Jest already picks up client/**/*.spec.ts, so no config change was needed.

Verified against a local 8.9.0-develop workspace with no custom emoji, which is the case that fails hardest. tsc --noEmit and eslint are clean on the changed files, and the client unit suite passes.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed category highlighting in the emoji picker while scrolling. The active category now updates more accurately when its section becomes visible, including the Custom category.