callstack / callstack/react-native-paper

refactor(banner): make hidden content inert and fix live region semantics

Đang mở
#5,055 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
TypeScript
Star
14.5k
Fork
2.2k
Merge trung bình
5 ngày 23 giờ
Pull request đã merge (30 ngày)
12

Mô tả

Part of #4990

Clean up Banner accessibility so hidden content is actually hidden/inert, live regions behave consistently across platforms, and animation callbacks only fire when a real show/hide transition happens.

Banner doesn't exist in MD3 anymore, but it's still a supported Paper extension, so this is mostly about making its behaviour internally sane and accessible rather than matching the Material spec exactly.

**Problems**

- Hidden Banner content is still mounted and reachable. It's only translated off-screen and clipped — screen readers can still see it and action buttons stay tabbable. Verified in the browser a11y tree: with `visible={false}`, both actions still have `tabIndex: 0` and can receive focus.
- `role="alert"` + `aria-live="polite"` doesn't really make sense. `alert` normally implies assertive + atomic, while Chrome currently ends up with `alert atomic live="polite"`.
- The live region currently does nothing on Android. RN maps `aria-live` to `accessibilityLiveRegion` on `View`, but not on `Text`, so the prop is effectively ignored there. It only works on web today.
- iOS has no live-region equivalent, so the message isn't announced there either.
- `actions` is unlimited and actions always sit below the message. Material allows max two.
- If a focused action disappears after the actions array changes, focus gets dumped at the top of the page.
- `onShowAnimationFinished` / `onHideAnimationFinished` fire on mount and again when `theme.animation.scale` changes, even though no visibility transition happened. Existing tests already call this out as probably a bug.

**Focus Areas**

- Make hidden content properly inert: no pointer interaction, no a11y exposure, no focus.
- Put the live region on a `View` so Android actually supports it, and keep it scoped to the message so action labels don't cause the whole banner to re-announce.
- Make `role` and `aria-live` agree: polite by default, assertive when explicitly requested.
- Announce manually on iOS without double-announcing on Android/web.
- Limit actions to two and let them reflow depending on available width.
- Restore focus if the currently focused action disappears.
- Run show/hide animations and callbacks only for actual `visible` transitions.

**Proposed API**

One new prop, everything else is behavioural:

```jsx

Your payment failed.

```

- `urgent?: boolean`
- `false` (default): `role="status"` + `aria-live="polite"`
- `true`: `role="alert"` + `aria-live="assertive"`; on iOS it interrupts instead of queueing

**Breaking changes**

- Banner children are unmounted once fully hidden, so local child state is lost after hiding.
- More than two actions are ignored, with a dev warning.

**Notes**

- #5016 retokenizes Banner (motion tokens + easing), but doesn't touch any of this accessibility behaviour.
- This should be checked separately with VoiceOver, TalkBack and the browser accessibility tree. They're different enough that testing only one isn't very meaningful.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Bắt đầu từ phần triển khai Banner và các bài kiểm thử animation hiện có; kiểm tra cách visible, actions, role/aria-live và animation callbacks hiện đang được xử lý. Được xem là hoàn tất khi nội dung bị ẩn không hoạt động, thông báo hoạt động đúng trên web, Android và iOS, actions tự xuống dòng và được giới hạn ở hai, focus được khôi phục, và callbacks chỉ chạy khi thực sự có chuyển đổi khả năng hiển thị.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
react-native, typescript
Lĩnh vực
accessibility, mobile
Loại issue
Tái cấu trúc
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
45/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.