Skip to content

Commit 8a0b57f

Browse files
authoredFeb 13, 2025··
feat(global-header): add spacer component (#412)
Signed-off-by: Christoph Jerolimov <jerolimov+git@redhat.com>

File tree

10 files changed

+156
-3
lines changed

10 files changed

+156
-3
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-global-header': patch
3+
---
4+
5+
Add new Spacer component

‎workspaces/global-header/mkdocs.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ plugins:
55

66
nav:
77
- About: index.md
8+
- Configuration: configuration.md

‎workspaces/global-header/plugins/global-header/dev/index.tsx

+15-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ import {
4242
GlobalHeader,
4343
globalHeaderPlugin,
4444
NotificationBanner,
45+
Slot,
46+
Spacer,
4547
} from '../src/plugin';
4648

4749
import {
@@ -224,9 +226,19 @@ createDevApp()
224226
<Providers
225227
mountPoints={{
226228
'global.header/component':
227-
defaultGlobalHeaderComponentsMountPoints.filter(
228-
mp => mp.config.type !== ComponentType.SEARCH,
229-
),
229+
defaultGlobalHeaderComponentsMountPoints.map(mp => {
230+
if (mp.config.type === ComponentType.SEARCH) {
231+
return {
232+
Component: Spacer,
233+
config: {
234+
type: ComponentType.SPACER,
235+
slot: Slot.HEADER_START,
236+
priority: 100, // the greater the number, the more to the left it will be
237+
},
238+
};
239+
}
240+
return mp;
241+
}),
230242
'global.header/create': defaultCreateDropdownMountPoints,
231243
'global.header/profile': defaultProfileDropdownMountPoints,
232244
}}

‎workspaces/global-header/plugins/global-header/report.api.md

+15
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export enum ComponentType {
1818
LIST = 'list',
1919
LOGOUT = 'logout',
2020
SEARCH = 'search',
21+
SPACER = 'spacer',
2122
}
2223

2324
// @public
@@ -222,5 +223,19 @@ export type SoftwareTemplatesSectionProps = {
222223
hideDivider?: boolean;
223224
};
224225

226+
// @public
227+
export const Spacer: ({
228+
growFactor,
229+
minWidth,
230+
}: SpacerProps) => React_2.JSX.Element;
231+
232+
// @public (undocumented)
233+
export interface SpacerProps {
234+
// (undocumented)
235+
growFactor?: number;
236+
// (undocumented)
237+
minWidth?: number | string;
238+
}
239+
225240
// (No @packageDocumentation comment for this package)
226241
```

‎workspaces/global-header/plugins/global-header/src/components/GlobalHeaderComponent.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ export const GlobalHeaderComponent = ({
9898

9999
const uniqueKey = `header-component-${index}`;
100100
switch (mp.config?.type) {
101+
case ComponentType.SPACER:
102+
return <mp.Component key={uniqueKey} />;
101103
case ComponentType.SEARCH:
102104
return (
103105
<ErrorBoundary key={uniqueKey}>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
19+
import { render } from '@testing-library/react';
20+
21+
import { Spacer } from './Spacer';
22+
23+
describe('Spacer', () => {
24+
it('render some default styles', () => {
25+
const { container } = render(<Spacer />);
26+
expect(container.firstElementChild?.getAttribute('style')).toEqual(
27+
'flex-grow: 1; min-width: 8px;',
28+
);
29+
});
30+
31+
it('accepts another grow factor', () => {
32+
const { container } = render(<Spacer growFactor={2} />);
33+
expect(container.firstElementChild?.getAttribute('style')).toEqual(
34+
'flex-grow: 2; min-width: 8px;',
35+
);
36+
});
37+
38+
it('accepts number min width', () => {
39+
const { container } = render(<Spacer minWidth={2} />);
40+
expect(container.firstElementChild?.getAttribute('style')).toEqual(
41+
'flex-grow: 1; min-width: 16px;',
42+
);
43+
});
44+
45+
it('accepts string min width', () => {
46+
const { container } = render(<Spacer minWidth="24px" />);
47+
expect(container.firstElementChild?.getAttribute('style')).toEqual(
48+
'flex-grow: 1; min-width: 24px;',
49+
);
50+
});
51+
52+
it('accepts both', () => {
53+
const { container } = render(<Spacer growFactor={2} minWidth={2} />);
54+
expect(container.firstElementChild?.getAttribute('style')).toEqual(
55+
'flex-grow: 2; min-width: 16px;',
56+
);
57+
});
58+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
19+
/**
20+
* @public
21+
*/
22+
export interface SpacerProps {
23+
growFactor?: number;
24+
minWidth?: number | string;
25+
}
26+
27+
/**
28+
* @public
29+
*/
30+
export const Spacer = ({ growFactor = 1, minWidth = 1 }: SpacerProps) => {
31+
return (
32+
<div
33+
style={{
34+
flexGrow: growFactor,
35+
minWidth: typeof minWidth === 'number' ? minWidth * 8 : minWidth,
36+
}}
37+
/>
38+
);
39+
};

‎workspaces/global-header/plugins/global-header/src/plugin.ts

+17
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export type { HeaderLinkProps } from './components/HeaderLinkComponent/HeaderLin
3030
export type { MenuItemConfig } from './components/HeaderDropdownComponent/MenuSection';
3131
export type { SoftwareTemplatesSectionProps } from './components/HeaderDropdownComponent/SoftwareTemplatesSection';
3232
export type { RegisterAComponentSectionProps } from './components/HeaderDropdownComponent/RegisterAComponentSection';
33+
export type { SpacerProps } from './components/Spacer/Spacer';
3334
export type {
3435
GlobalHeaderComponentMountPoint,
3536
GlobalHeaderComponentMountPointConfig,
@@ -229,6 +230,22 @@ export const LogoutButton: React.ComponentType = globalHeaderPlugin.provide(
229230
}),
230231
);
231232

233+
/**
234+
* Spacer component that allow users to add a flexibel spacing between components.
235+
*
236+
* Supports two props: `growFactor` with default 1 and `minWidth` width default 8 pixels.
237+
*
238+
* @public
239+
*/
240+
export const Spacer = globalHeaderPlugin.provide(
241+
createComponentExtension({
242+
name: 'Spacer',
243+
component: {
244+
lazy: () => import('./components/Spacer/Spacer').then(m => m.Spacer),
245+
},
246+
}),
247+
);
248+
232249
/**
233250
* NotificationBanner
234251
*

‎workspaces/global-header/plugins/global-header/src/types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ export enum Slot {
3636
* @public
3737
*/
3838
export enum ComponentType {
39+
/**
40+
* Global Header spacer
41+
*/
42+
SPACER = 'spacer',
3943
/**
4044
* Global Header Component dropdown button
4145
*/

0 commit comments

Comments
 (0)