Skip to content

Commit 86d09b5

Browse files
fix(LoginPage): allow brand props passthrough make brand optional (#12194)
* fix(LoginPage): allow brand props passthrough and fix brand appearing without props Signed-off-by: Mohamed Fall <ps.hackmaster@gmail.com> * test(LoginPage): add tests for brand image rendering scenarios Signed-off-by: Mohamed Fall <ps.hackmaster@gmail.com> * test(LoginPage): enhance brand image tests with aria-label and className attributes Signed-off-by: Mohamed Fall <ps.hackmaster@gmail.com> * fix(LoginPage): update examples to include new brandImgProps for Brand customization Signed-off-by: Mohamed Fall <ps.hackmaster@gmail.com> * Removed hover class from example --------- Signed-off-by: Mohamed Fall <ps.hackmaster@gmail.com> Co-authored-by: Eric Olkowski <70952936+thatblindgeye@users.noreply.github.com>
1 parent d589d3a commit 86d09b5

File tree

5 files changed

+138
-5
lines changed

5 files changed

+138
-5
lines changed

packages/react-core/src/components/LoginPage/LoginPage.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Fragment } from 'react';
22
import { css } from '@patternfly/react-styles';
33

44
import { BackgroundImage } from '../BackgroundImage';
5-
import { Brand } from '../Brand';
5+
import { Brand, BrandProps } from '../Brand';
66
import { List, ListVariant } from '../List';
77

88
import { Login } from './Login';
@@ -21,6 +21,8 @@ export interface LoginPageProps extends React.HTMLProps<HTMLDivElement> {
2121
brandImgSrc?: string;
2222
/** Attribute that specifies the alt text of the brand image for the login page */
2323
brandImgAlt?: string;
24+
/** Additional props for the brand image for the login page */
25+
brandImgProps?: BrandProps;
2426
/** Attribute that specifies the URL of the background image for the login page */
2527
backgroundImgSrc?: string;
2628
/** Content rendered inside of the text component of the login page */
@@ -50,6 +52,7 @@ export const LoginPage: React.FunctionComponent<LoginPageProps> = ({
5052
className = '',
5153
brandImgSrc = '',
5254
brandImgAlt = '',
55+
brandImgProps,
5356
backgroundImgSrc = '',
5457
footerListItems = null,
5558
textContent = '',
@@ -65,7 +68,7 @@ export const LoginPage: React.FunctionComponent<LoginPageProps> = ({
6568
}: LoginPageProps) => {
6669
const HeaderBrand = (
6770
<Fragment>
68-
<Brand src={brandImgSrc} alt={brandImgAlt} />
71+
{(brandImgSrc || brandImgProps?.src) && <Brand src={brandImgSrc} alt={brandImgAlt} {...brandImgProps} />}
6972
</Fragment>
7073
);
7174
const Header = <LoginHeader headerBrand={HeaderBrand} />;

packages/react-core/src/components/LoginPage/__tests__/LoginPage.test.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Fragment } from 'react';
2-
import { render } from '@testing-library/react';
2+
import { render, screen } from '@testing-library/react';
33

44
import { LoginPage } from '../LoginPage';
55
import { ListVariant } from '../../List';
@@ -26,3 +26,40 @@ test('check loginpage example against snapshot', () => {
2626
);
2727
expect(asFragment()).toMatchSnapshot();
2828
});
29+
30+
test('brand is absent without brandImgSrc and brandImgProps.src', () => {
31+
const { asFragment } = render(<LoginPage loginTitle="Log into your account" />);
32+
expect(asFragment()).toMatchSnapshot();
33+
});
34+
35+
test('brand is present with brandImgSrc prop', () => {
36+
const { asFragment } = render(<LoginPage brandImgSrc="Brand src" loginTitle="Log into your account" />);
37+
expect(asFragment()).toMatchSnapshot();
38+
});
39+
40+
test('brandImgProps successfully renders brand with props', () => {
41+
render(
42+
<LoginPage
43+
brandImgProps={{ src: 'Brand src', alt: 'Pf-logo', 'aria-label': 'PatternFly logo', className: 'custom-class' }}
44+
loginTitle="Log into your account"
45+
/>
46+
);
47+
const brandImg = screen.getByRole('img', { name: 'PatternFly logo' });
48+
expect(brandImg).toHaveAttribute('src', 'Brand src');
49+
expect(brandImg).toHaveAttribute('alt', 'Pf-logo');
50+
expect(brandImg).toHaveAttribute('aria-label', 'PatternFly logo');
51+
expect(brandImg).toHaveClass('custom-class');
52+
});
53+
54+
test('Brand is rendered correctly with both brandImgSrc and brandImgProps, prioritizing brandImgProps.src', () => {
55+
render(
56+
<LoginPage
57+
brandImgSrc="Brand-src-that-should-be-ignored"
58+
brandImgProps={{ src: 'Brand-src-from-props', alt: 'Pf-logo from props' }}
59+
loginTitle="Log into your account"
60+
/>
61+
);
62+
const brandImg = screen.getByRole('img', { name: 'Pf-logo from props' });
63+
expect(brandImg).toHaveAttribute('src', 'Brand-src-from-props');
64+
expect(brandImg).toHaveAttribute('alt', 'Pf-logo from props');
65+
});

packages/react-core/src/components/LoginPage/__tests__/__snapshots__/LoginPage.test.tsx.snap

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,97 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`brand is absent without brandImgSrc and brandImgProps.src 1`] = `
4+
<DocumentFragment>
5+
<div
6+
class="pf-v6-c-login"
7+
>
8+
<div
9+
class="pf-v6-c-login__container"
10+
>
11+
<header
12+
class="pf-v6-c-login__header"
13+
/>
14+
<main
15+
class="pf-v6-c-login__main"
16+
>
17+
<div
18+
class="pf-v6-c-login__main-header"
19+
>
20+
<h2
21+
class="pf-v6-c-title pf-m-3xl"
22+
data-ouia-component-id="OUIA-Generated-Title-2"
23+
data-ouia-component-type="PF6/Title"
24+
data-ouia-safe="true"
25+
>
26+
Log into your account
27+
</h2>
28+
</div>
29+
<div
30+
class="pf-v6-c-login__main-body"
31+
/>
32+
</main>
33+
<footer
34+
class="pf-v6-c-login__footer"
35+
>
36+
<p />
37+
<ul
38+
class="pf-v6-c-list"
39+
/>
40+
</footer>
41+
</div>
42+
</div>
43+
</DocumentFragment>
44+
`;
45+
46+
exports[`brand is present with brandImgSrc prop 1`] = `
47+
<DocumentFragment>
48+
<div
49+
class="pf-v6-c-login"
50+
>
51+
<div
52+
class="pf-v6-c-login__container"
53+
>
54+
<header
55+
class="pf-v6-c-login__header"
56+
>
57+
<img
58+
alt=""
59+
class="pf-v6-c-brand"
60+
src="Brand src"
61+
/>
62+
</header>
63+
<main
64+
class="pf-v6-c-login__main"
65+
>
66+
<div
67+
class="pf-v6-c-login__main-header"
68+
>
69+
<h2
70+
class="pf-v6-c-title pf-m-3xl"
71+
data-ouia-component-id="OUIA-Generated-Title-3"
72+
data-ouia-component-type="PF6/Title"
73+
data-ouia-safe="true"
74+
>
75+
Log into your account
76+
</h2>
77+
</div>
78+
<div
79+
class="pf-v6-c-login__main-body"
80+
/>
81+
</main>
82+
<footer
83+
class="pf-v6-c-login__footer"
84+
>
85+
<p />
86+
<ul
87+
class="pf-v6-c-list"
88+
/>
89+
</footer>
90+
</div>
91+
</div>
92+
</DocumentFragment>
93+
`;
94+
395
exports[`check loginpage example against snapshot 1`] = `
496
<DocumentFragment>
597
<div

packages/react-core/src/components/LoginPage/examples/LoginPage.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import GitlabIcon from '@patternfly/react-icons/dist/esm/icons/gitlab-icon';
3232
### Basic
3333

3434
By default, a login page requires users to enter both a username and a password into their respective fields. The username must always be a required field, but you can make the password optional by passing the `isPasswordRequired` property to the `<LoginForm>`.
35+
36+
This example uses `brandImgProps` to pass the brand image source, alt text, and an extra class, which will be preferred over `brandImgSrc` when both are provided.
3537
```ts file='./LoginPageBasic.tsx' isFullscreen
3638

3739
```

packages/react-core/src/components/LoginPage/examples/LoginPageBasic.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ export const SimpleLoginPage: React.FunctionComponent = () => {
114114
return (
115115
<LoginPage
116116
footerListVariants={ListVariant.inline}
117-
brandImgSrc={brandImg}
118-
brandImgAlt="PatternFly logo"
117+
brandImgProps={{ src: brandImg, alt: 'PatternFly logo' }}
119118
backgroundImgSrc="/assets/images/pf-background.svg"
120119
footerListItems={listItem}
121120
textContent="This is placeholder text only. Use this area to place any information or introductory message about your application that may be relevant to users."

0 commit comments

Comments
 (0)