From c025c453535114e7c9ef3a4443c08164c7f030ec Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 5 Mar 2026 13:16:43 +0700 Subject: [PATCH 01/13] fix: button is announced without a state --- src/components/Button/index.tsx | 7 ++++++- src/components/ButtonWithDropdownMenu/index.tsx | 3 +++ .../implementation/BaseGenericPressable.tsx | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 2334c953e73a..f9336b7093db 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -1,7 +1,7 @@ import {useIsFocused} from '@react-navigation/native'; import type {ForwardedRef} from 'react'; import React, {useCallback, useMemo, useState} from 'react'; -import type {GestureResponderEvent, LayoutChangeEvent, StyleProp, TextStyle, ViewStyle} from 'react-native'; +import type {AccessibilityState, GestureResponderEvent, LayoutChangeEvent, StyleProp, TextStyle, ViewStyle} from 'react-native'; import {StyleSheet, View} from 'react-native'; import ActivityIndicator from '@components/ActivityIndicator'; import Icon from '@components/Icon'; @@ -139,6 +139,9 @@ type ButtonProps = Partial & /** Accessibility label for the component */ accessibilityLabel?: string; + /** Accessibility state to pass to the pressable */ + accessibilityState?: AccessibilityState; + /** The icon asset to display to the left of the text */ icon?: IconAsset | null; @@ -278,6 +281,7 @@ function Button({ id = '', testID = undefined, accessibilityLabel = '', + accessibilityState, isSplitButton = false, link = false, isContentCentered = false, @@ -530,6 +534,7 @@ function Button({ testID={testID} accessibilityLabel={accessibilityLabel} role={getButtonRole(isNested)} + accessibilityState={accessibilityState} hoverDimmingValue={1} onHoverIn={!isDisabled || !shouldStayNormalOnDisable ? () => setIsHovered(true) : undefined} onHoverOut={!isDisabled || !shouldStayNormalOnDisable ? () => setIsHovered(false) : undefined} diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 56e8a81e0033..23d549228347 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -189,6 +189,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM secondLineText={secondLineText} icon={icon} sentryLabel={sentryLabel} + accessibilityState={!isSplitButton ? {expanded: isMenuVisible} : undefined} /> {isSplitButton && ( @@ -207,6 +208,8 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM innerStyles={[styles.dropDownButtonCartIconContainerPadding, innerStyleDropButton, isButtonSizeSmall && styles.dropDownButtonCartIcon]} enterKeyEventListenerPriority={enterKeyEventListenerPriority} sentryLabel={sentryLabel} + accessibilityState={{expanded: isMenuVisible}} + accessibilityLabel={isMenuVisible ? CONST.ACCESSIBILITY_LABELS.COLLAPSE : CONST.ACCESSIBILITY_LABELS.EXPAND} > diff --git a/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx b/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx index b62140832848..2249726d62dc 100644 --- a/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx +++ b/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx @@ -202,6 +202,7 @@ function GenericPressable({ aria-disabled={isDisabled} aria-checked={accessibilityState?.checked} aria-selected={accessibilityState?.selected} + aria-expanded={accessibilityState?.expanded} aria-keyshortcuts={keyboardShortcut && `${keyboardShortcut.modifiers.join('')}+${keyboardShortcut.shortcutKey}`} // ios-only form of inputs onMagicTap={!isDisabled ? voidOnPressHandler : undefined} From b490f94f403029755663a9374ba85ced608f139e Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 5 Mar 2026 13:17:46 +0700 Subject: [PATCH 02/13] add patch package --- ...abric-accessibility-expanded-collapsed.patch | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch diff --git a/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch b/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch new file mode 100644 index 000000000000..304177405ea5 --- /dev/null +++ b/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +@@ -1313,9 +1313,12 @@ + "mixed", "a checkbox, radio button, or other widget which is both checked and unchecked")]; + } +- if (accessibilityState.expanded.value_or(false)) { +- [valueComponents +- addObject:RCTLocalizedString("expanded", "a menu, dialog, accordian panel, or other widget which is expanded")]; +- } ++ if (accessibilityState.expanded.has_value()) { ++ [valueComponents addObject:accessibilityState.expanded.value() ++ ? RCTLocalizedString("expanded", "a menu, dialog, accordian panel, or other widget which is expanded") ++ : RCTLocalizedString("collapsed", "a menu, dialog, accordian panel, or other widget which is collapsed")]; ++ } + + if (accessibilityState.busy) { From e5538c794f8e163aff9ee8c0daa3ea6ab4475823 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 5 Mar 2026 13:39:08 +0700 Subject: [PATCH 03/13] fix lint --- ...0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch b/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch index 304177405ea5..f2d69bc9121e 100644 --- a/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch +++ b/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch @@ -1,7 +1,7 @@ diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm --- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm -@@ -1313,9 +1313,12 @@ +@@ -1314,8 +1314,9 @@ "mixed", "a checkbox, radio button, or other widget which is both checked and unchecked")]; } - if (accessibilityState.expanded.value_or(false)) { From 756d56f6e1a2e2029b1f375a5c1d8a687717a33e Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 5 Mar 2026 14:53:06 +0700 Subject: [PATCH 04/13] fix validate patch --- patches/react-native/details.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/patches/react-native/details.md b/patches/react-native/details.md index f7b4c34790d1..f1f777b7a9af 100644 --- a/patches/react-native/details.md +++ b/patches/react-native/details.md @@ -217,3 +217,10 @@ - Upstream PR/issue: This should ideally be the default behavior upstream, but no PR has been filed yet. - E/App issue: [#83000](https://github.com/Expensify/App/issues/83000) - PR introducing patch: [#83256](https://github.com/Expensify/App/pull/83256) + +### [react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch](react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch) + +- Reason: Fixes a bug in Fabric's (`RCTViewComponentView.mm`) accessibility state handling where the "collapsed" state is never announced by VoiceOver on iOS. The old architecture (`RCTView.m`) correctly handles both "expanded" and "collapsed", but Fabric only announced "expanded" (when `expanded=true`) and silently skipped announcing "collapsed" (when `expanded=false`). This patch changes the condition from `value_or(false)` to `has_value()` so that both states are properly announced. +- Upstream PR/issue: https://github.com/facebook/react-native/issues/XXXXX (Fabric regression vs Paper behavior) +- E/App issue: [#76929](https://github.com/Expensify/App/issues/76929) +- PR introducing patch: [#84244](https://github.com/Expensify/App/pull/84244) From 729b82bf01b6caa4ad4cf617f37498b227fea8ef Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 5 Mar 2026 15:12:50 +0700 Subject: [PATCH 05/13] remove useless label --- src/components/ButtonWithDropdownMenu/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 23d549228347..c1f63915a142 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -209,7 +209,6 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM enterKeyEventListenerPriority={enterKeyEventListenerPriority} sentryLabel={sentryLabel} accessibilityState={{expanded: isMenuVisible}} - accessibilityLabel={isMenuVisible ? CONST.ACCESSIBILITY_LABELS.COLLAPSE : CONST.ACCESSIBILITY_LABELS.EXPAND} > From 6f6e3d62ba03c92a03b1a74b070bffdbed077ef0 Mon Sep 17 00:00:00 2001 From: daledah Date: Fri, 13 Mar 2026 00:58:20 +0700 Subject: [PATCH 06/13] Add accessibilityHint for the button --- src/components/Button/index.tsx | 5 +++++ src/components/ButtonWithDropdownMenu/index.tsx | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 25ee4f94ce72..8fd4d9ca1293 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -148,6 +148,9 @@ type ButtonProps = Partial & /** Accessibility label for the component */ accessibilityLabel?: string; + /** Accessibility hint for the component */ + accessibilityHint?: string; + /** Accessibility state to pass to the pressable */ accessibilityState?: AccessibilityState; @@ -286,6 +289,7 @@ function Button({ id = '', testID = undefined, accessibilityLabel = '', + accessibilityHint, accessibilityState, link = false, isContentCentered = false, @@ -526,6 +530,7 @@ function Button({ id={id} testID={testID} accessibilityLabel={accessibilityLabel} + accessibilityHint={accessibilityHint} role={getButtonRole(isNested)} accessibilityState={accessibilityState} hoverDimmingValue={1} diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index a323326e3095..4ec047f8421f 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -146,6 +146,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM ); const splitButtonWrapperStyle = isSplitButton ? [styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter] : {}; const isTextTooLong = customText && customText?.length > 6; + const dropdownAccessibilityHint = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.COLLAPSE : CONST.ACCESSIBILITY_LABELS.EXPAND; const handlePress = useCallback( (event?: GestureResponderEvent | KeyboardEvent) => { @@ -196,6 +197,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM iconRightHoverFill={hasError ? theme.icon : undefined} sentryLabel={sentryLabel} accessibilityState={!isSplitButton ? {expanded: isMenuVisible} : undefined} + accessibilityHint={!isSplitButton ? dropdownAccessibilityHint : undefined} /> {isSplitButton && ( @@ -215,6 +217,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM enterKeyEventListenerPriority={enterKeyEventListenerPriority} sentryLabel={sentryLabel} accessibilityState={{expanded: isMenuVisible}} + accessibilityHint={dropdownAccessibilityHint} > From c8fcf024e5c69a863010e4eea8b2c8b353697a38 Mon Sep 17 00:00:00 2001 From: daledah Date: Fri, 13 Mar 2026 01:03:56 +0700 Subject: [PATCH 07/13] minor fix --- src/components/ButtonWithDropdownMenu/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 4ec047f8421f..a564b0747f23 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -146,7 +146,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM ); const splitButtonWrapperStyle = isSplitButton ? [styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter] : {}; const isTextTooLong = customText && customText?.length > 6; - const dropdownAccessibilityHint = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.COLLAPSE : CONST.ACCESSIBILITY_LABELS.EXPAND; + const dropdownAccessibilityHint = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.EXPAND : CONST.ACCESSIBILITY_LABELS.COLLAPSE; const handlePress = useCallback( (event?: GestureResponderEvent | KeyboardEvent) => { From f544e712228d9cd722abbe53f41a23132e9800ea Mon Sep 17 00:00:00 2001 From: daledah Date: Fri, 13 Mar 2026 12:07:29 +0700 Subject: [PATCH 08/13] remove useless prop --- patches/react-native/details.md | 9 +-------- ...abric-accessibility-expanded-collapsed.patch | 17 ----------------- src/components/Button/index.tsx | 7 +------ src/components/ButtonWithDropdownMenu/index.tsx | 2 -- .../implementation/BaseGenericPressable.tsx | 1 - 5 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch diff --git a/patches/react-native/details.md b/patches/react-native/details.md index 0f8fbf5939b5..727a15e55b71 100644 --- a/patches/react-native/details.md +++ b/patches/react-native/details.md @@ -223,11 +223,4 @@ - Reason: This patch prevents app crashes by soft-logging the exception when JS try to send events to native views even if they are removed from view hierarchy. The approach follows existing patterns in the same file where similar events are already handled this way and is based on suggestions from other developers in upstream discussions. - Upstream PR/issue: [#49077](https://github.com/facebook/react-native/issues/49077) [#7493](https://github.com/software-mansion/react-native-reanimated/issues/7493) - E/App issue: [#82611](https://github.com/Expensify/App/issues/82611) -- PR introducing patch: [#84303](https://github.com/Expensify/App/pull/84303) - -### [react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch](react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch) - -- Reason: Fixes a bug in Fabric's (`RCTViewComponentView.mm`) accessibility state handling where the "collapsed" state is never announced by VoiceOver on iOS. The old architecture (`RCTView.m`) correctly handles both "expanded" and "collapsed", but Fabric only announced "expanded" (when `expanded=true`) and silently skipped announcing "collapsed" (when `expanded=false`). This patch changes the condition from `value_or(false)` to `has_value()` so that both states are properly announced. -- Upstream PR/issue: https://github.com/facebook/react-native/issues/XXXXX (Fabric regression vs Paper behavior) -- E/App issue: [#76929](https://github.com/Expensify/App/issues/76929) -- PR introducing patch: [#84244](https://github.com/Expensify/App/pull/84244) +- PR introducing patch: [#84303](https://github.com/Expensify/App/pull/84303) \ No newline at end of file diff --git a/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch b/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch deleted file mode 100644 index f2d69bc9121e..000000000000 --- a/patches/react-native/react-native+0.81.4+029+fix-fabric-accessibility-expanded-collapsed.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm ---- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm -+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm -@@ -1314,8 +1314,9 @@ - "mixed", "a checkbox, radio button, or other widget which is both checked and unchecked")]; - } -- if (accessibilityState.expanded.value_or(false)) { -- [valueComponents -- addObject:RCTLocalizedString("expanded", "a menu, dialog, accordian panel, or other widget which is expanded")]; -- } -+ if (accessibilityState.expanded.has_value()) { -+ [valueComponents addObject:accessibilityState.expanded.value() -+ ? RCTLocalizedString("expanded", "a menu, dialog, accordian panel, or other widget which is expanded") -+ : RCTLocalizedString("collapsed", "a menu, dialog, accordian panel, or other widget which is collapsed")]; -+ } - - if (accessibilityState.busy) { diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 8fd4d9ca1293..229dc4475ed1 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -1,7 +1,7 @@ import {useIsFocused} from '@react-navigation/native'; import type {ForwardedRef} from 'react'; import React, {useCallback, useMemo, useState} from 'react'; -import type {AccessibilityState, GestureResponderEvent, LayoutChangeEvent, StyleProp, TextStyle, ViewStyle} from 'react-native'; +import type {GestureResponderEvent, LayoutChangeEvent, StyleProp, TextStyle, ViewStyle} from 'react-native'; import {StyleSheet, View} from 'react-native'; import ActivityIndicator from '@components/ActivityIndicator'; import Icon from '@components/Icon'; @@ -151,9 +151,6 @@ type ButtonProps = Partial & /** Accessibility hint for the component */ accessibilityHint?: string; - /** Accessibility state to pass to the pressable */ - accessibilityState?: AccessibilityState; - /** The text for the button label */ text?: string; @@ -290,7 +287,6 @@ function Button({ testID = undefined, accessibilityLabel = '', accessibilityHint, - accessibilityState, link = false, isContentCentered = false, isPressOnEnterActive, @@ -532,7 +528,6 @@ function Button({ accessibilityLabel={accessibilityLabel} accessibilityHint={accessibilityHint} role={getButtonRole(isNested)} - accessibilityState={accessibilityState} hoverDimmingValue={1} onHoverIn={!isDisabled || !shouldStayNormalOnDisable ? () => setIsHovered(true) : undefined} onHoverOut={!isDisabled || !shouldStayNormalOnDisable ? () => setIsHovered(false) : undefined} diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index a564b0747f23..06bd4f089c34 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -196,7 +196,6 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM iconRightFill={hasError ? theme.icon : undefined} iconRightHoverFill={hasError ? theme.icon : undefined} sentryLabel={sentryLabel} - accessibilityState={!isSplitButton ? {expanded: isMenuVisible} : undefined} accessibilityHint={!isSplitButton ? dropdownAccessibilityHint : undefined} /> @@ -216,7 +215,6 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM innerStyles={[styles.dropDownButtonCartIconContainerPadding, innerStyleDropButton, isButtonSizeSmall && styles.dropDownButtonCartIcon]} enterKeyEventListenerPriority={enterKeyEventListenerPriority} sentryLabel={sentryLabel} - accessibilityState={{expanded: isMenuVisible}} accessibilityHint={dropdownAccessibilityHint} > diff --git a/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx b/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx index 2249726d62dc..b62140832848 100644 --- a/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx +++ b/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx @@ -202,7 +202,6 @@ function GenericPressable({ aria-disabled={isDisabled} aria-checked={accessibilityState?.checked} aria-selected={accessibilityState?.selected} - aria-expanded={accessibilityState?.expanded} aria-keyshortcuts={keyboardShortcut && `${keyboardShortcut.modifiers.join('')}+${keyboardShortcut.shortcutKey}`} // ios-only form of inputs onMagicTap={!isDisabled ? voidOnPressHandler : undefined} From 7fe5f32de905ee7fc77f29677fbf7faeeb3fb305 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 19 Mar 2026 11:39:12 +0700 Subject: [PATCH 09/13] fix test --- patches/react-native/details.md | 2 +- .../Pressable/GenericPressable/implementation/index.native.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/react-native/details.md b/patches/react-native/details.md index 727a15e55b71..a869464f0684 100644 --- a/patches/react-native/details.md +++ b/patches/react-native/details.md @@ -223,4 +223,4 @@ - Reason: This patch prevents app crashes by soft-logging the exception when JS try to send events to native views even if they are removed from view hierarchy. The approach follows existing patterns in the same file where similar events are already handled this way and is based on suggestions from other developers in upstream discussions. - Upstream PR/issue: [#49077](https://github.com/facebook/react-native/issues/49077) [#7493](https://github.com/software-mansion/react-native-reanimated/issues/7493) - E/App issue: [#82611](https://github.com/Expensify/App/issues/82611) -- PR introducing patch: [#84303](https://github.com/Expensify/App/pull/84303) \ No newline at end of file +- PR introducing patch: [#84303](https://github.com/Expensify/App/pull/84303) diff --git a/src/components/Pressable/GenericPressable/implementation/index.native.tsx b/src/components/Pressable/GenericPressable/implementation/index.native.tsx index ec71d8ab4da6..c8b0df808577 100644 --- a/src/components/Pressable/GenericPressable/implementation/index.native.tsx +++ b/src/components/Pressable/GenericPressable/implementation/index.native.tsx @@ -7,9 +7,9 @@ function NativeGenericPressable({ref, ...props}: PressableProps) { ); From 1b2c1090f3bdf3d62916de860de6f4f983e72624 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 19 Mar 2026 21:43:51 +0700 Subject: [PATCH 10/13] fix annouce on web --- src/components/Button/index.tsx | 6 +----- src/components/ButtonWithDropdownMenu/index.tsx | 7 ++++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 405dafe33535..cb38207651a8 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -149,9 +149,6 @@ type ButtonProps = Partial & /** Accessibility label for the component */ accessibilityLabel?: string; - /** Accessibility hint for the component */ - accessibilityHint?: string; - /** The text for the button label */ text?: string; @@ -287,7 +284,6 @@ function Button({ id = '', testID = undefined, accessibilityLabel = '', - accessibilityHint, link = false, isContentCentered = false, isPressOnEnterActive, @@ -531,7 +527,7 @@ function Button({ id={id} testID={testID} accessibilityLabel={accessibilityLabel} - accessibilityHint={accessibilityHint} + accessibilityHint="" role={getButtonRole(isNested)} hoverDimmingValue={1} onHoverIn={!isDisabled || !shouldStayNormalOnDisable ? () => setIsHovered(true) : undefined} diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 06bd4f089c34..49b1e24807a7 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -146,7 +146,8 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM ); const splitButtonWrapperStyle = isSplitButton ? [styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter] : {}; const isTextTooLong = customText && customText?.length > 6; - const dropdownAccessibilityHint = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.EXPAND : CONST.ACCESSIBILITY_LABELS.COLLAPSE; + const accessibilityExpandState = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.EXPAND : CONST.ACCESSIBILITY_LABELS.COLLAPSE; + const accessibilityLabel = `${accessibilityExpandState}, ${customText}`; const handlePress = useCallback( (event?: GestureResponderEvent | KeyboardEvent) => { @@ -196,7 +197,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM iconRightFill={hasError ? theme.icon : undefined} iconRightHoverFill={hasError ? theme.icon : undefined} sentryLabel={sentryLabel} - accessibilityHint={!isSplitButton ? dropdownAccessibilityHint : undefined} + accessibilityLabel={!isSplitButton ? accessibilityLabel : undefined} /> {isSplitButton && ( @@ -215,7 +216,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM innerStyles={[styles.dropDownButtonCartIconContainerPadding, innerStyleDropButton, isButtonSizeSmall && styles.dropDownButtonCartIcon]} enterKeyEventListenerPriority={enterKeyEventListenerPriority} sentryLabel={sentryLabel} - accessibilityHint={dropdownAccessibilityHint} + accessibilityLabel={accessibilityLabel} > From 5283522db201196abc664075d343b691159cd5e7 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 19 Mar 2026 21:54:21 +0700 Subject: [PATCH 11/13] fix jest test --- src/components/Button/index.tsx | 6 +++++- src/components/ButtonWithDropdownMenu/index.tsx | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index cb38207651a8..434702af4f56 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -149,6 +149,9 @@ type ButtonProps = Partial & /** Accessibility label for the component */ accessibilityLabel?: string; + /** Accessibility hint for the component */ + accessibilityHint?: string; + /** The text for the button label */ text?: string; @@ -284,6 +287,7 @@ function Button({ id = '', testID = undefined, accessibilityLabel = '', + accessibilityHint = undefined, link = false, isContentCentered = false, isPressOnEnterActive, @@ -527,12 +531,12 @@ function Button({ id={id} testID={testID} accessibilityLabel={accessibilityLabel} - accessibilityHint="" role={getButtonRole(isNested)} hoverDimmingValue={1} onHoverIn={!isDisabled || !shouldStayNormalOnDisable ? () => setIsHovered(true) : undefined} onHoverOut={!isDisabled || !shouldStayNormalOnDisable ? () => setIsHovered(false) : undefined} sentryLabel={sentryLabel} + accessibilityHint={accessibilityHint} > {shouldBlendOpacity && } {renderContent()} diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 49b1e24807a7..75708b8dad24 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -198,6 +198,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM iconRightHoverFill={hasError ? theme.icon : undefined} sentryLabel={sentryLabel} accessibilityLabel={!isSplitButton ? accessibilityLabel : undefined} + accessibilityHint="" /> {isSplitButton && ( @@ -217,6 +218,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM enterKeyEventListenerPriority={enterKeyEventListenerPriority} sentryLabel={sentryLabel} accessibilityLabel={accessibilityLabel} + accessibilityHint="" > From 2a59efe2c21f8eeb41c2e639f6c8407fc1ccaa71 Mon Sep 17 00:00:00 2001 From: daledah Date: Tue, 24 Mar 2026 11:05:25 +0700 Subject: [PATCH 12/13] add new const --- src/CONST/index.ts | 2 ++ src/components/ButtonWithDropdownMenu/index.tsx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 4789213e0fff..1b5ff94b9f58 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -5898,7 +5898,9 @@ const CONST = { ACCESSIBILITY_LABELS: { COLLAPSE: 'Collapse', + COLLAPSED: 'Collapsed', EXPAND: 'Expand', + EXPANDED: 'Expanded', ERROR: 'Error', }, diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 75708b8dad24..38a466ad3e02 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -146,7 +146,7 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM ); const splitButtonWrapperStyle = isSplitButton ? [styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter] : {}; const isTextTooLong = customText && customText?.length > 6; - const accessibilityExpandState = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.EXPAND : CONST.ACCESSIBILITY_LABELS.COLLAPSE; + const accessibilityExpandState = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.EXPANDED : CONST.ACCESSIBILITY_LABELS.COLLAPSED; const accessibilityLabel = `${accessibilityExpandState}, ${customText}`; const handlePress = useCallback( From 6f3f17c7df93548586f308c5d848d2a82d187f6a Mon Sep 17 00:00:00 2001 From: daledah Date: Tue, 24 Mar 2026 14:30:53 +0700 Subject: [PATCH 13/13] fix bot comments --- src/components/ButtonWithDropdownMenu/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 38a466ad3e02..5d164462a9b1 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -147,7 +147,8 @@ function ButtonWithDropdownMenu({ref, ...props}: ButtonWithDropdownM const splitButtonWrapperStyle = isSplitButton ? [styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter] : {}; const isTextTooLong = customText && customText?.length > 6; const accessibilityExpandState = isMenuVisible ? CONST.ACCESSIBILITY_LABELS.EXPANDED : CONST.ACCESSIBILITY_LABELS.COLLAPSED; - const accessibilityLabel = `${accessibilityExpandState}, ${customText}`; + const buttonText = customText ?? selectedItem?.text ?? ''; + const accessibilityLabel = `${accessibilityExpandState}, ${buttonText}`; const handlePress = useCallback( (event?: GestureResponderEvent | KeyboardEvent) => {