diff --git a/UNRELEASED.md b/UNRELEASED.md index 811457c8c37..3b59959015d 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -6,6 +6,8 @@ - Added `external` prop to `ResourceList` ([#2408](https://github.com/Shopify/polaris-react/pull/2408)) - Added `onMouseEnter` and `onTouchStart` props to `Button` ([#2409](https://github.com/Shopify/polaris-react/pull/2409)) +- Added `footerActionAlignment` prop to control `` footer action alignment, defaults to `'right'` +- Added `reverse` prop to `` to control visual render order ([#2407](https://github.com/Shopify/polaris-react/pull/2407)) ### Bug fixes @@ -15,6 +17,7 @@ - Fixed an issue which caused HSL colors to not display in Edge ((#2418)[https://github.com/Shopify/polaris-react/pull/2418]) - Fixed an issue where the dropzone component jumped from an extra-large layout to a layout based on the width of it's container ([#2412](https://github.com/Shopify/polaris-react/pull/2412)) - Fixed a race condition in DatePicker ([#2373](https://github.com/Shopify/polaris-react/pull/2373)) +- Updated `Card` footer actions to be right aligned by default again ([#2407](https://github.com/Shopify/polaris-react/pull/2407)) ### Documentation diff --git a/src/components/ButtonGroup/ButtonGroup.scss b/src/components/ButtonGroup/ButtonGroup.scss index 676cfe6723e..be9c14f9e06 100644 --- a/src/components/ButtonGroup/ButtonGroup.scss +++ b/src/components/ButtonGroup/ButtonGroup.scss @@ -16,6 +16,10 @@ $item-spacing: spacing(tight); margin-left: (-1 * $item-spacing); } +.Reverse { + flex-direction: row-reverse; +} + .Item { margin-top: $item-spacing; margin-left: $item-spacing; diff --git a/src/components/ButtonGroup/ButtonGroup.tsx b/src/components/ButtonGroup/ButtonGroup.tsx index ffdb5fc6798..3ca0e18964c 100644 --- a/src/components/ButtonGroup/ButtonGroup.tsx +++ b/src/components/ButtonGroup/ButtonGroup.tsx @@ -13,6 +13,8 @@ export interface ButtonGroupProps { connectedTop?: boolean; /** Button components */ children?: React.ReactNode; + //* Reverse the visual order of the buttons while maintaining DOM order */ + reverse?: boolean; } export function ButtonGroup({ @@ -20,12 +22,14 @@ export function ButtonGroup({ segmented, fullWidth, connectedTop, + reverse = false, }: ButtonGroupProps) { const className = classNames( styles.ButtonGroup, segmented && styles.segmented, fullWidth && styles.fullWidth, connectedTop && styles.connectedTop, + reverse && styles.Reverse, ); const contents = elementChildren(children).map((child, index) => ( diff --git a/src/components/Card/Card.scss b/src/components/Card/Card.scss index ebf4f01bbbb..f4d80b65b45 100644 --- a/src/components/Card/Card.scss +++ b/src/components/Card/Card.scss @@ -93,13 +93,17 @@ .Footer { display: flex; - justify-content: flex-start; + justify-content: flex-end; padding: 0 spacing() spacing(); @include page-content-when-not-fully-condensed { padding: 0 spacing(loose) spacing(loose); } + &.LeftJustified { + justify-content: flex-start; + } + .Section-subdued + & { border-top: border(); padding: spacing(loose); diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index d66b9ba6b94..ffa061f67a2 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -29,6 +29,8 @@ export interface CardProps { secondaryFooterActions?: ComplexAction[]; /** The content of the disclosure button rendered when there is more than one secondary footer action */ secondaryFooterActionsDisclosureText?: string; + /** Alignment of the footer actions on the card, defaults to right */ + footerActionAlignment?: 'right' | 'left'; } // TypeScript can't generate types that correctly infer the typing of @@ -49,6 +51,7 @@ export const Card: React.FunctionComponent & { primaryFooterAction, secondaryFooterActions, secondaryFooterActionsDisclosureText, + footerActionAlignment = 'right', }: CardProps) { const i18n = useI18n(); @@ -94,10 +97,15 @@ export const Card: React.FunctionComponent & { const footerMarkup = primaryFooterActionMarkup || secondaryFooterActionsMarkup ? ( -
- - {secondaryFooterActionsMarkup} +
+ {primaryFooterActionMarkup} + {secondaryFooterActionsMarkup}
) : null; diff --git a/src/components/Card/README.md b/src/components/Card/README.md index a8541bd2b0a..99f7f715019 100644 --- a/src/components/Card/README.md +++ b/src/components/Card/README.md @@ -237,7 +237,7 @@ Use for less important card actions, or actions merchants may do before reviewin -Use footer actions for a card’s most important actions, or actions merchants should do after reviewing the contents of the card. For example, merchants should review the contents of a shipment before an important action like adding tracking information. +Use footer actions for a card’s most important actions, or actions merchants should do after reviewing the contents of the card. For example, merchants should review the contents of a shipment before an important action like adding tracking information. Footer actions can be left or right aligned with the `footerActionAlignment` prop. diff --git a/src/components/Card/tests/Card.test.tsx b/src/components/Card/tests/Card.test.tsx index f2c492201a2..9c8490b58be 100644 --- a/src/components/Card/tests/Card.test.tsx +++ b/src/components/Card/tests/Card.test.tsx @@ -4,7 +4,15 @@ import { trigger, findByTestID, } from 'test-utilities/legacy'; -import {Card, Badge, Button, Popover, ActionList} from 'components'; +import {mountWithApp} from 'test-utilities'; +import { + Card, + Badge, + Button, + ButtonGroup, + Popover, + ActionList, +} from 'components'; import {WithinContentContext} from '../../../utilities/within-content-context'; import {Section} from '../components'; @@ -74,6 +82,44 @@ describe('', () => { expect(card.find(Card.Header)).toHaveLength(1); }); + describe('footerActionAlignment prop', () => { + it('renders right-aligned if not supplied', () => { + const card = mountWithApp( + +

Some card content.

+
, + ); + + expect(card).toContainReactComponent(ButtonGroup, {reverse: true}); + }); + + it('renders right-aligned if set to "right"', () => { + const card = mountWithApp( + +

Some card content.

+
, + ); + + expect(card).toContainReactComponent(ButtonGroup, {reverse: true}); + }); + + it('renders left-aligned if set to "left"', () => { + const card = mountWithApp( + +

Some card content.

+
, + ); + + expect(card).toContainReactComponent(ButtonGroup, {reverse: false}); + }); + }); + it('renders a primary footer action', () => { const card = mountWithAppProvider(