mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 15:06:32 +00:00
fix(costs): row buttons, settle-up rows and share toggles say what they are about to a screen reader
A screen reader lists a page's buttons together, and the costs views gave
it twenty "Edit" and "Delete" buttons with nothing to tell them apart.
- Edit and delete on an expense name the expense ("Edit: Dinner"), edit
and undo on a payment name who paid whom, on desktop and phone.
- A settle-up row shows only initials in its avatars, its names lived in a
tooltip; the row now carries them for assistive tech too, and its Settle
button says who pays whom and how much.
- The search field of every searchable select (currency, time zone,
category) was read out as "..."; it now says Search in the user's
language.
- The public link toggles on the phone share sheet and the journey share
toggles say whether they are on (aria-pressed), not only by colour.
- Japanese still said "you" in the settle-up lines.
Refs #2604
This commit is contained in:
@@ -71,7 +71,7 @@ describe('CustomSelect', () => {
|
||||
render(<CustomSelect value="" onChange={onChange} options={OPTIONS} searchable={true} />);
|
||||
await user.click(screen.getByRole('button')); // open
|
||||
|
||||
const searchInput = screen.getByPlaceholderText('...');
|
||||
const searchInput = screen.getByPlaceholderText('common.search');
|
||||
await user.type(searchInput, 'ban');
|
||||
|
||||
// Only Banana should remain, Apple and Cherry should be filtered out
|
||||
@@ -257,8 +257,8 @@ describe('CustomSelect', () => {
|
||||
render(<CustomSelect ariaLabel="Choose fruit" value="" onChange={onChange} options={OPTIONS} searchable />);
|
||||
const trigger = screen.getByRole('button', { name: 'Choose fruit' });
|
||||
await user.click(trigger);
|
||||
expect(screen.getByPlaceholderText('...')).toHaveFocus();
|
||||
await user.type(screen.getByPlaceholderText('...'), 'ban');
|
||||
expect(screen.getByPlaceholderText('common.search')).toHaveFocus();
|
||||
await user.type(screen.getByPlaceholderText('common.search'), 'ban');
|
||||
await user.keyboard('{ArrowDown}{Enter}');
|
||||
expect(onChange).toHaveBeenCalledWith('banana');
|
||||
expect(trigger).toHaveFocus();
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect, useId } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { ChevronDown, Check } from 'lucide-react'
|
||||
import { useAnchoredPosition, scrollAnchorIntoView } from '../../hooks/useAnchoredPosition'
|
||||
import { useTranslation } from '../../i18n'
|
||||
|
||||
interface SelectOption {
|
||||
// Callers use both string keys and numeric ids (e.g. day/place ids) as values, and
|
||||
@@ -91,6 +92,7 @@ export default function CustomSelect({
|
||||
const searchRef = useRef<HTMLInputElement>(null)
|
||||
const keyboardDirection = useRef<'first' | 'last' | null>(null)
|
||||
const menuId = useId()
|
||||
const { t } = useTranslation()
|
||||
|
||||
// Follows the trigger while the sheet scrolls and while the on-screen keyboard
|
||||
// resizes the viewport, instead of freezing at the rect measured on open (#1999).
|
||||
@@ -258,7 +260,8 @@ export default function CustomSelect({
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={e => setSearch(e.target.value)}
|
||||
placeholder="..."
|
||||
placeholder={t('common.search')}
|
||||
aria-label={t('common.search')}
|
||||
style={{
|
||||
width: '100%', border: '1px solid var(--border-secondary)', borderRadius: 6,
|
||||
padding: '5px 8px', fontSize: 'calc(12px * var(--fs-scale-body, 1))', outline: 'none', fontFamily: 'inherit',
|
||||
|
||||
Reference in New Issue
Block a user