diff --git a/.changeset/puny-garlics-stop.md b/.changeset/puny-garlics-stop.md
new file mode 100644
index 0000000000..064435dc68
--- /dev/null
+++ b/.changeset/puny-garlics-stop.md
@@ -0,0 +1,5 @@
+---
+
+---
+
+
diff --git a/packages/agentic/components/src/components/tab/tab.test.tsx b/packages/agentic/components/src/components/tab/tab.test.tsx
index e8e921f1dc..f3abf06a1d 100644
--- a/packages/agentic/components/src/components/tab/tab.test.tsx
+++ b/packages/agentic/components/src/components/tab/tab.test.tsx
@@ -28,6 +28,98 @@ function getRootStyle(component: RenderResult): ViewStyle {
}
describe('Tab', () => {
+ it.each((['iconOnly', 'iconAndText'] as const).flatMap((layout) => [false, true].map((disabled) => ({ layout, disabled }))))(
+ 'TAB-003 TAB-006 retains the ordinary icon across selection changes for $layout disabled=$disabled',
+ async ({ layout, disabled }) => {
+ const icon = { imageSource: { uri: 'ordinary.png' }, testID: 'ordinary-icon' };
+ const scene = (selected: boolean) =>
+ layout === 'iconOnly' ? (
+
+ ) : (
+
+ );
+ const component = await render(scene(false));
+
+ for (const selected of [false, true, false]) {
+ await component.rerender(scene(selected));
+ const ordinary = component.getByTestId('ordinary-icon');
+ expect(ordinary.props.source).toEqual({ uri: 'ordinary.png' });
+ expect(ordinary.props.accessible).toBe(false);
+ expect(StyleSheet.flatten(ordinary.props.style)).toMatchObject({ width: 20, height: 20 });
+ expect(getRoot(component).props.accessibilityState).toMatchObject({ disabled, selected });
+ }
+ },
+ );
+
+ it.each([false, true].flatMap((selected) => [false, true].map((disabled) => ({ selected, disabled }))))(
+ 'TAB-005 applies the same foreground to the icon and both text layers for selected=$selected disabled=$disabled',
+ async ({ selected, disabled }) => {
+ const component = await renderTab({
+ controls: 'files-panel',
+ content: 'Files',
+ icon: { fontSource: { codepoint: 0x2606, fontFamily: 'Arial' }, testID: 'ordinary-icon' },
+ selected,
+ disabled,
+ });
+ const colors = defaultFlexTokens.color;
+ const foreground = selected ? 'foregroundNeutralOnloud' : 'foregroundNeutralPrimary';
+ for (const interaction of ['rest', 'hover', 'pressed'] as const) {
+ if (interaction === 'hover') {
+ await fireEvent(getRoot(component), 'hoverIn', {});
+ } else if (interaction === 'pressed') {
+ await fireEvent(getRoot(component), 'pressIn', {});
+ }
+ const expected = disabled
+ ? colors.foregroundNeutralDisabled
+ : interaction === 'rest'
+ ? colors[foreground]
+ : colors[interaction][foreground];
+ const labels = component.getAllByText('Files', { includeHiddenElements: true });
+ expect(labels).toHaveLength(2);
+ expect(labels.map((label) => StyleSheet.flatten(label.props.style).color)).toEqual([expected, expected]);
+ expect(StyleSheet.flatten(component.getByText('\u2606', { includeHiddenElements: true }).props.style).color).toBe(expected);
+ expect(component.getByTestId('ordinary-icon').props.accessible).toBe(false);
+ }
+ },
+ );
+
+ it.each(
+ (['standalone', 'group'] as const).flatMap((owner) =>
+ [false, true].flatMap((selected) => [false, true].map((disabled) => ({ owner, selected, disabled }))),
+ ),
+ )('TAB-007 merges caller state beneath $owner selected=$selected disabled=$disabled semantics', async ({ owner, selected, disabled }) => {
+ const state = { busy: true, selected: !selected, disabled: !disabled };
+ const component = await render(
+ owner === 'standalone' ? (
+
+ ) : (
+
+
+
+
+ ),
+ );
+ const root = component.getByRole('tab', { name: 'Files' });
+
+ expect(root.props.accessibilityState).toEqual({ busy: true, disabled, selected });
+ expect(root.props.accessibilityControls).toBe('files-panel');
+ expect(root.props.focusable).toBe(!disabled && (owner === 'standalone' || selected));
+ });
+
it('keeps its internal focus ref when the consumer omits ref', async () => {
let registeredRef: FocusTarget | undefined;
const contextValue: TabListContextValue = {