Skip to content
Merged
2 changes: 1 addition & 1 deletion packages/react-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
20 changes: 20 additions & 0 deletions packages/react-core/src/components/Card/CardSubtitle.tsx
Original file line number Diff line number Diff line change
@@ -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<CardSubtitleProps> = ({
children = null,
id = '',
...props
}: CardSubtitleProps) => (
<div {...props} id={id} className={css(styles.cardSubtitle)}>
{children}
</div>
);
CardSubtitle.displayName = 'CardSubtitle';
6 changes: 6 additions & 0 deletions packages/react-core/src/components/Card/CardTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement> {
/** Content rendered inside the CardTitle */
Expand All @@ -10,23 +11,28 @@ export interface CardTitleProps extends React.HTMLProps<HTMLDivElement> {
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<CardTitleProps> = ({
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 (
<div className={css(styles.cardTitle)}>
<Component className={css(styles.cardTitleText, className)} id={titleId || undefined} {...props}>
{children}
</Component>
{subtitle && <CardSubtitle id={subtitleId}>{subtitle}</CardSubtitle>}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -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(<CardSubtitle>text</CardSubtitle>);
expect(asFragment()).toMatchSnapshot();
});

test('extra props are spread to the root element', () => {
const testId = 'card-subtitle';

render(<CardSubtitle data-testid={testId} />);
expect(screen.getByTestId(testId)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CardSubtitle renders with PatternFly Core styles 1`] = `
<DocumentFragment>
<div
class="pf-v6-c-card__subtitle"
id=""
>
text
</div>
</DocumentFragment>
`;
17 changes: 16 additions & 1 deletion packages/react-core/src/components/Card/examples/Card.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,20 @@ import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';

Basic cards typically have a `<CardTitle>`, `<CardBody>` and `<CardFooter>`. You may omit these components as needed, but it is recommended to at least include a `<CardBody>` 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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcoker Added subtitle and actions that is similar to what is in core.

This card demonstrates having an image, action, and subtitle in a single card.

```ts file='./CardSubtitleActions.tsx' isBeta

```

Expand Down Expand Up @@ -71,6 +84,8 @@ Select the "actions hasNoOffset" checkbox in the example below to illustrate thi

```



### Title inline with images and actions

Moving `<CardTitle>` within the `<CardHeader>` will style it inline with any images or actions.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Card, CardTitle, CardBody, CardFooter } from '@patternfly/react-core';

export const CardSubtitle: React.FunctionComponent = () => (
<Card ouiaId="CardSubtitle">
<CardTitle subtitle="Subtitle">Title</CardTitle>
<CardBody>Body</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
);
Original file line number Diff line number Diff line change
@@ -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<boolean>(false);
const [isChecked, setIsChecked] = useState<boolean>(false);
const [hasNoOffset, setHasNoOffset] = useState<boolean>(false);

const onSelect = () => {
setIsOpen(!isOpen);
};
const onClick = (checked: boolean) => {
setIsChecked(checked);
};
const toggleOffset = (checked: boolean) => {
setHasNoOffset(checked);
};

const dropdownItems = (
<>
<DropdownItem key="action">Action</DropdownItem>
{/* Prevent default onClick functionality for example purposes */}
<DropdownItem key="link" to="#" onClick={(event: any) => event.preventDefault()}>
Link
</DropdownItem>
<DropdownItem key="disabled action" isDisabled>
Disabled Action
</DropdownItem>
<DropdownItem key="disabled link" isDisabled to="#" onClick={(event: any) => event.preventDefault()}>
Disabled Link
</DropdownItem>
<Divider component="li" key="separator" />
<DropdownItem key="separated action">Separated Action</DropdownItem>
<DropdownItem key="separated link" to="#" onClick={(event: any) => event.preventDefault()}>
Separated Link
</DropdownItem>
</>
);

const headerActions = (
<>
<Dropdown
onSelect={onSelect}
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle
ref={toggleRef}
isExpanded={isOpen}
onClick={() => setIsOpen(!isOpen)}
variant="plain"
aria-label="Card header images and actions example kebab toggle"
icon={<EllipsisVIcon />}
/>
)}
isOpen={isOpen}
onOpenChange={(isOpen: boolean) => setIsOpen(isOpen)}
>
<DropdownList>{dropdownItems}</DropdownList>
</Dropdown>
<Checkbox
isChecked={isChecked}
onChange={(_event, checked) => onClick(checked)}
aria-label="card checkbox example"
id="check-1"
name="check1"
/>
</>
);

return (
<>
<Checkbox
label="actions hasNoOffset"
isChecked={hasNoOffset}
onChange={(_event, checked) => toggleOffset(checked)}
aria-label="remove actions offset"
id="toggle-actions-offset"
name="toggle-actions-offset"
/>
<div style={{ marginTop: '15px' }}>
<Card>
<CardHeader actions={{ actions: headerActions, hasNoOffset }}>
<Brand src={pfLogo} alt="PatternFly logo" style={{ width: '300px' }} />
</CardHeader>
<CardTitle subtitle="Subtitle">Title</CardTitle>
<CardBody>Body</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
</div>
</>
);
};
2 changes: 1 addition & 1 deletion packages/react-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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:^",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-icons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/react-styles/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/react-tokens/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
18 changes: 9 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:^"
Expand All @@ -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:^"
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading