diff --git a/.gitignore b/.gitignore index 986dbca5699..88265987011 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ www/public # Local Netlify folder .netlify +.claude/ diff --git a/src/ActionRow/ActionRow.test.tsx b/src/ActionRow/ActionRow.test.tsx new file mode 100644 index 00000000000..4f1e9e62fe2 --- /dev/null +++ b/src/ActionRow/ActionRow.test.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import ActionRow from '.'; + +describe('', () => { + describe('stacked mode', () => { + it('renders children in reverse DOM order so primary action leads focus', () => { + const { getAllByRole } = render( + + + + , + ); + const buttons = getAllByRole('button'); + expect(buttons[0]).toHaveTextContent('Primary'); + expect(buttons[1]).toHaveTextContent('Secondary'); + }); + }); + + describe('horizontal mode', () => { + it('renders children in original DOM order', () => { + const { getAllByRole } = render( + + + + , + ); + const buttons = getAllByRole('button'); + expect(buttons[0]).toHaveTextContent('Secondary'); + expect(buttons[1]).toHaveTextContent('Primary'); + }); + }); +}); diff --git a/src/ActionRow/README.md b/src/ActionRow/README.md index 7ad955b1e70..7499d728e3d 100644 --- a/src/ActionRow/README.md +++ b/src/ActionRow/README.md @@ -16,7 +16,7 @@ notes: | A layout utility for the common use case of aligning buttons, links or text in a row in a control bar or nav. -ActionRow assumes that its last child is the primary action and lays out actions so that the last item is in a primary location. If horizontal, the primary action sits on the right. If stacked, the primary action sits at the top of the stack (this is done via `flex-direction: column-reverse;`). +ActionRow assumes that its last child is the primary action and lays out actions so that the last item is in a primary location. If horizontal, the primary action sits on the right. If stacked, the primary action sits at the top of the stack — the component reverses the DOM order of children so that keyboard focus order matches the visual order (primary action is reached first). ## Basic Usage diff --git a/src/ActionRow/_index.scss b/src/ActionRow/_index.scss index 341c335ac86..045dea595de 100644 --- a/src/ActionRow/_index.scss +++ b/src/ActionRow/_index.scss @@ -17,7 +17,7 @@ display: flex; flex-grow: 1; align-items: center; - flex-direction: column-reverse; + flex-direction: column; justify-content: center; & > * { @@ -25,7 +25,7 @@ } & > * + * { - margin-bottom: var(--pgn-spacing-action-row-gap-y); + margin-top: var(--pgn-spacing-action-row-gap-y); } } diff --git a/src/ActionRow/index.tsx b/src/ActionRow/index.tsx index 5a698762f24..61f5d53b187 100644 --- a/src/ActionRow/index.tsx +++ b/src/ActionRow/index.tsx @@ -18,6 +18,12 @@ function ActionRow({ children, ...props }: ActionRowProps) { + // Reverse DOM order when stacked so the primary action (last child) is first + // in the tab sequence, matching its visual position at the top of the stack. + const orderedChildren = isStacked + ? React.Children.toArray(children).reverse() + : children; + return React.createElement( as, { @@ -27,7 +33,7 @@ function ActionRow({ 'pgn__action-row-stacked': isStacked, }), }, - children, + orderedChildren, ); }