diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 6e797e2f696..252a9cf3446 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -54,7 +54,7 @@ "tslib": "^2.8.1" }, "devDependencies": { - "@patternfly/patternfly": "6.5.0-prerelease.12", + "@patternfly/patternfly": "6.5.0-prerelease.14", "case-anything": "^3.1.2", "css": "^3.0.0", "fs-extra": "^11.3.0" diff --git a/packages/react-core/src/components/Card/CardSubtitle.tsx b/packages/react-core/src/components/Card/CardSubtitle.tsx new file mode 100644 index 00000000000..63e27ac915a --- /dev/null +++ b/packages/react-core/src/components/Card/CardSubtitle.tsx @@ -0,0 +1,20 @@ +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/Card/card'; + +export interface CardSubtitleProps { + /** Content rendered inside the description. */ + children?: React.ReactNode; + /** Id of the description. */ + id?: string; +} + +export const CardSubtitle: React.FunctionComponent = ({ + children = null, + id = '', + ...props +}: CardSubtitleProps) => ( +
+ {children} +
+); +CardSubtitle.displayName = 'CardSubtitle'; diff --git a/packages/react-core/src/components/Card/CardTitle.tsx b/packages/react-core/src/components/Card/CardTitle.tsx index 2df2ced37f7..17333c150f4 100644 --- a/packages/react-core/src/components/Card/CardTitle.tsx +++ b/packages/react-core/src/components/Card/CardTitle.tsx @@ -2,6 +2,7 @@ import { useContext } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Card/card'; import { CardContext } from './Card'; +import { CardSubtitle } from './CardSubtitle'; export interface CardTitleProps extends React.HTMLProps { /** Content rendered inside the CardTitle */ @@ -10,23 +11,28 @@ export interface CardTitleProps extends React.HTMLProps { className?: string; /** Sets the base component to render. defaults to div */ component?: keyof React.JSX.IntrinsicElements; + /** @beta Subtitle of the card title */ + subtitle?: React.ReactNode; } export const CardTitle: React.FunctionComponent = ({ children, className, component = 'div', + subtitle, ...props }: CardTitleProps) => { const { cardId } = useContext(CardContext); const Component = component as any; const titleId = cardId ? `${cardId}-title` : ''; + const subtitleId = cardId ? `${cardId}-subtitle` : ''; return (
{children} + {subtitle && {subtitle}}
); }; diff --git a/packages/react-core/src/components/Card/__tests__/CardSubtitle.test.tsx b/packages/react-core/src/components/Card/__tests__/CardSubtitle.test.tsx new file mode 100644 index 00000000000..26eb5157b78 --- /dev/null +++ b/packages/react-core/src/components/Card/__tests__/CardSubtitle.test.tsx @@ -0,0 +1,16 @@ +import { render, screen } from '@testing-library/react'; +import { CardSubtitle } from '../CardSubtitle'; + +describe('CardSubtitle', () => { + test('renders with PatternFly Core styles', () => { + const { asFragment } = render(text); + expect(asFragment()).toMatchSnapshot(); + }); + + test('extra props are spread to the root element', () => { + const testId = 'card-subtitle'; + + render(); + expect(screen.getByTestId(testId)).toBeInTheDocument(); + }); +}); diff --git a/packages/react-core/src/components/Card/__tests__/__snapshots__/CardSubtitle.test.tsx.snap b/packages/react-core/src/components/Card/__tests__/__snapshots__/CardSubtitle.test.tsx.snap new file mode 100644 index 00000000000..0ff2585ae23 --- /dev/null +++ b/packages/react-core/src/components/Card/__tests__/__snapshots__/CardSubtitle.test.tsx.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CardSubtitle renders with PatternFly Core styles 1`] = ` + +
+ text +
+
+`; diff --git a/packages/react-core/src/components/Card/examples/Card.md b/packages/react-core/src/components/Card/examples/Card.md index 671249655bf..6f90777fc9b 100644 --- a/packages/react-core/src/components/Card/examples/Card.md +++ b/packages/react-core/src/components/Card/examples/Card.md @@ -28,7 +28,20 @@ import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon'; Basic cards typically have a ``, `` and ``. You may omit these components as needed, but it is recommended to at least include a `` to provide details about the card item. -```ts file='./CardBasic.tsx' +```ts file='./CardBasic.tsx' + +``` +### Card with subtitle + +A basic card that also has a subtitle + +```ts file='./CardSubtitle.tsx' isBeta + +``` +### Card with subtitle and Actions +This card demonstrates having an image, action, and subtitle in a single card. + +```ts file='./CardSubtitleActions.tsx' isBeta ``` @@ -71,6 +84,8 @@ Select the "actions hasNoOffset" checkbox in the example below to illustrate thi ``` + + ### Title inline with images and actions Moving `` within the `` will style it inline with any images or actions. diff --git a/packages/react-core/src/components/Card/examples/CardSubtitle.tsx b/packages/react-core/src/components/Card/examples/CardSubtitle.tsx new file mode 100644 index 00000000000..71697f493ce --- /dev/null +++ b/packages/react-core/src/components/Card/examples/CardSubtitle.tsx @@ -0,0 +1,9 @@ +import { Card, CardTitle, CardBody, CardFooter } from '@patternfly/react-core'; + +export const CardSubtitle: React.FunctionComponent = () => ( + + Title + Body + Footer + +); diff --git a/packages/react-core/src/components/Card/examples/CardSubtitleActions.tsx b/packages/react-core/src/components/Card/examples/CardSubtitleActions.tsx new file mode 100644 index 00000000000..4277b06834b --- /dev/null +++ b/packages/react-core/src/components/Card/examples/CardSubtitleActions.tsx @@ -0,0 +1,107 @@ +import { useState } from 'react'; +import { + Brand, + Card, + CardHeader, + CardTitle, + CardBody, + CardFooter, + Checkbox, + Dropdown, + DropdownList, + DropdownItem, + MenuToggle, + MenuToggleElement, + Divider +} from '@patternfly/react-core'; +import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import pfLogo from '../../assets/PF-HorizontalLogo-Color.svg'; + +export const CardWithImageAndActions: React.FunctionComponent = () => { + const [isOpen, setIsOpen] = useState(false); + const [isChecked, setIsChecked] = useState(false); + const [hasNoOffset, setHasNoOffset] = useState(false); + + const onSelect = () => { + setIsOpen(!isOpen); + }; + const onClick = (checked: boolean) => { + setIsChecked(checked); + }; + const toggleOffset = (checked: boolean) => { + setHasNoOffset(checked); + }; + + const dropdownItems = ( + <> + Action + {/* Prevent default onClick functionality for example purposes */} + event.preventDefault()}> + Link + + + Disabled Action + + event.preventDefault()}> + Disabled Link + + + Separated Action + event.preventDefault()}> + Separated Link + + + ); + + const headerActions = ( + <> + ) => ( + setIsOpen(!isOpen)} + variant="plain" + aria-label="Card header images and actions example kebab toggle" + icon={} + /> + )} + isOpen={isOpen} + onOpenChange={(isOpen: boolean) => setIsOpen(isOpen)} + > + {dropdownItems} + + onClick(checked)} + aria-label="card checkbox example" + id="check-1" + name="check1" + /> + + ); + + return ( + <> + toggleOffset(checked)} + aria-label="remove actions offset" + id="toggle-actions-offset" + name="toggle-actions-offset" + /> +
+ + + + + Title + Body + Footer + +
+ + ); +}; diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index 345b9190ed8..5a0b3ee24fc 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -23,7 +23,7 @@ "test:a11y": "patternfly-a11y --config patternfly-a11y.config" }, "dependencies": { - "@patternfly/patternfly": "6.5.0-prerelease.12", + "@patternfly/patternfly": "6.5.0-prerelease.14", "@patternfly/react-charts": "workspace:^", "@patternfly/react-code-editor": "workspace:^", "@patternfly/react-core": "workspace:^", diff --git a/packages/react-icons/package.json b/packages/react-icons/package.json index 93e54de17d1..5c6a2a7c42e 100644 --- a/packages/react-icons/package.json +++ b/packages/react-icons/package.json @@ -33,7 +33,7 @@ "@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4", - "@patternfly/patternfly": "6.5.0-prerelease.12", + "@patternfly/patternfly": "6.5.0-prerelease.14", "fs-extra": "^11.3.0", "tslib": "^2.8.1" }, diff --git a/packages/react-styles/package.json b/packages/react-styles/package.json index 923363024ae..399debeeba0 100644 --- a/packages/react-styles/package.json +++ b/packages/react-styles/package.json @@ -19,7 +19,7 @@ "clean": "rimraf dist css" }, "devDependencies": { - "@patternfly/patternfly": "6.5.0-prerelease.12", + "@patternfly/patternfly": "6.5.0-prerelease.14", "change-case": "^5.4.4", "fs-extra": "^11.3.0" }, diff --git a/packages/react-tokens/package.json b/packages/react-tokens/package.json index 80b95955e11..e5e9c60428b 100644 --- a/packages/react-tokens/package.json +++ b/packages/react-tokens/package.json @@ -30,7 +30,7 @@ }, "devDependencies": { "@adobe/css-tools": "^4.4.4", - "@patternfly/patternfly": "6.5.0-prerelease.12", + "@patternfly/patternfly": "6.5.0-prerelease.14", "fs-extra": "^11.3.0" } } diff --git a/yarn.lock b/yarn.lock index 909d4f77ea9..4b92c46246d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4516,10 +4516,10 @@ __metadata: languageName: node linkType: hard -"@patternfly/patternfly@npm:6.5.0-prerelease.12": - version: 6.5.0-prerelease.12 - resolution: "@patternfly/patternfly@npm:6.5.0-prerelease.12" - checksum: 10c0/a07d7ccbde0bdcdfa03877678ee73c741f1dc6774c0fe96db24e308f637e68035684bf3758e6acf3e2c51c46f27d320eff2189e85bfdeb0c9104dd18d33ae771 +"@patternfly/patternfly@npm:6.5.0-prerelease.14": + version: 6.5.0-prerelease.14 + resolution: "@patternfly/patternfly@npm:6.5.0-prerelease.14" + checksum: 10c0/d2bca43a2b4c98767b81dc5569eb5960866c9e7b757276b69aa8eacc06414723e3a58b434c7f1b46e416fe02474dbc333707e6c6a82ca05201900458d74ca548 languageName: node linkType: hard @@ -4617,7 +4617,7 @@ __metadata: version: 0.0.0-use.local resolution: "@patternfly/react-core@workspace:packages/react-core" dependencies: - "@patternfly/patternfly": "npm:6.5.0-prerelease.12" + "@patternfly/patternfly": "npm:6.5.0-prerelease.14" "@patternfly/react-icons": "workspace:^" "@patternfly/react-styles": "workspace:^" "@patternfly/react-tokens": "workspace:^" @@ -4638,7 +4638,7 @@ __metadata: resolution: "@patternfly/react-docs@workspace:packages/react-docs" dependencies: "@patternfly/documentation-framework": "npm:^6.28.9" - "@patternfly/patternfly": "npm:6.5.0-prerelease.12" + "@patternfly/patternfly": "npm:6.5.0-prerelease.14" "@patternfly/patternfly-a11y": "npm:5.1.0" "@patternfly/react-charts": "workspace:^" "@patternfly/react-code-editor": "workspace:^" @@ -4678,7 +4678,7 @@ __metadata: "@fortawesome/free-brands-svg-icons": "npm:^5.15.4" "@fortawesome/free-regular-svg-icons": "npm:^5.15.4" "@fortawesome/free-solid-svg-icons": "npm:^5.15.4" - "@patternfly/patternfly": "npm:6.5.0-prerelease.12" + "@patternfly/patternfly": "npm:6.5.0-prerelease.14" fs-extra: "npm:^11.3.0" tslib: "npm:^2.8.1" peerDependencies: @@ -4763,7 +4763,7 @@ __metadata: version: 0.0.0-use.local resolution: "@patternfly/react-styles@workspace:packages/react-styles" dependencies: - "@patternfly/patternfly": "npm:6.5.0-prerelease.12" + "@patternfly/patternfly": "npm:6.5.0-prerelease.14" change-case: "npm:^5.4.4" fs-extra: "npm:^11.3.0" languageName: unknown @@ -4805,7 +4805,7 @@ __metadata: resolution: "@patternfly/react-tokens@workspace:packages/react-tokens" dependencies: "@adobe/css-tools": "npm:^4.4.4" - "@patternfly/patternfly": "npm:6.5.0-prerelease.12" + "@patternfly/patternfly": "npm:6.5.0-prerelease.14" fs-extra: "npm:^11.3.0" languageName: unknown linkType: soft