Skip to content

Commit

Permalink
feat(global-header): add spacer component (#412)
Browse files Browse the repository at this point in the history
Signed-off-by: Christoph Jerolimov <[email protected]>
  • Loading branch information
christoph-jerolimov authored Feb 13, 2025
1 parent 2f73462 commit 8a0b57f
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 3 deletions.
5 changes: 5 additions & 0 deletions workspaces/global-header/.changeset/empty-tools-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-global-header': patch
---

Add new Spacer component
1 change: 1 addition & 0 deletions workspaces/global-header/mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ plugins:

nav:
- About: index.md
- Configuration: configuration.md
18 changes: 15 additions & 3 deletions workspaces/global-header/plugins/global-header/dev/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import {
GlobalHeader,
globalHeaderPlugin,
NotificationBanner,
Slot,
Spacer,
} from '../src/plugin';

import {
Expand Down Expand Up @@ -224,9 +226,19 @@ createDevApp()
<Providers
mountPoints={{
'global.header/component':
defaultGlobalHeaderComponentsMountPoints.filter(
mp => mp.config.type !== ComponentType.SEARCH,
),
defaultGlobalHeaderComponentsMountPoints.map(mp => {
if (mp.config.type === ComponentType.SEARCH) {
return {
Component: Spacer,
config: {
type: ComponentType.SPACER,
slot: Slot.HEADER_START,
priority: 100, // the greater the number, the more to the left it will be
},
};
}
return mp;
}),
'global.header/create': defaultCreateDropdownMountPoints,
'global.header/profile': defaultProfileDropdownMountPoints,
}}
Expand Down
15 changes: 15 additions & 0 deletions workspaces/global-header/plugins/global-header/report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum ComponentType {
LIST = 'list',
LOGOUT = 'logout',
SEARCH = 'search',
SPACER = 'spacer',
}

// @public
Expand Down Expand Up @@ -222,5 +223,19 @@ export type SoftwareTemplatesSectionProps = {
hideDivider?: boolean;
};

// @public
export const Spacer: ({
growFactor,
minWidth,
}: SpacerProps) => React_2.JSX.Element;

// @public (undocumented)
export interface SpacerProps {
// (undocumented)
growFactor?: number;
// (undocumented)
minWidth?: number | string;
}

// (No @packageDocumentation comment for this package)
```
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ export const GlobalHeaderComponent = ({

const uniqueKey = `header-component-${index}`;
switch (mp.config?.type) {
case ComponentType.SPACER:
return <mp.Component key={uniqueKey} />;
case ComponentType.SEARCH:
return (
<ErrorBoundary key={uniqueKey}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import React from 'react';

import { render } from '@testing-library/react';

import { Spacer } from './Spacer';

describe('Spacer', () => {
it('render some default styles', () => {
const { container } = render(<Spacer />);
expect(container.firstElementChild?.getAttribute('style')).toEqual(
'flex-grow: 1; min-width: 8px;',
);
});

it('accepts another grow factor', () => {
const { container } = render(<Spacer growFactor={2} />);
expect(container.firstElementChild?.getAttribute('style')).toEqual(
'flex-grow: 2; min-width: 8px;',
);
});

it('accepts number min width', () => {
const { container } = render(<Spacer minWidth={2} />);
expect(container.firstElementChild?.getAttribute('style')).toEqual(
'flex-grow: 1; min-width: 16px;',
);
});

it('accepts string min width', () => {
const { container } = render(<Spacer minWidth="24px" />);
expect(container.firstElementChild?.getAttribute('style')).toEqual(
'flex-grow: 1; min-width: 24px;',
);
});

it('accepts both', () => {
const { container } = render(<Spacer growFactor={2} minWidth={2} />);
expect(container.firstElementChild?.getAttribute('style')).toEqual(
'flex-grow: 2; min-width: 16px;',
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import React from 'react';

/**
* @public
*/
export interface SpacerProps {
growFactor?: number;
minWidth?: number | string;
}

/**
* @public
*/
export const Spacer = ({ growFactor = 1, minWidth = 1 }: SpacerProps) => {
return (
<div
style={{
flexGrow: growFactor,
minWidth: typeof minWidth === 'number' ? minWidth * 8 : minWidth,
}}
/>
);
};
17 changes: 17 additions & 0 deletions workspaces/global-header/plugins/global-header/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type { HeaderLinkProps } from './components/HeaderLinkComponent/HeaderLin
export type { MenuItemConfig } from './components/HeaderDropdownComponent/MenuSection';
export type { SoftwareTemplatesSectionProps } from './components/HeaderDropdownComponent/SoftwareTemplatesSection';
export type { RegisterAComponentSectionProps } from './components/HeaderDropdownComponent/RegisterAComponentSection';
export type { SpacerProps } from './components/Spacer/Spacer';
export type {
GlobalHeaderComponentMountPoint,
GlobalHeaderComponentMountPointConfig,
Expand Down Expand Up @@ -229,6 +230,22 @@ export const LogoutButton: React.ComponentType = globalHeaderPlugin.provide(
}),
);

/**
* Spacer component that allow users to add a flexibel spacing between components.
*
* Supports two props: `growFactor` with default 1 and `minWidth` width default 8 pixels.
*
* @public
*/
export const Spacer = globalHeaderPlugin.provide(
createComponentExtension({
name: 'Spacer',
component: {
lazy: () => import('./components/Spacer/Spacer').then(m => m.Spacer),
},
}),
);

/**
* NotificationBanner
*
Expand Down
4 changes: 4 additions & 0 deletions workspaces/global-header/plugins/global-header/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export enum Slot {
* @public
*/
export enum ComponentType {
/**
* Global Header spacer
*/
SPACER = 'spacer',
/**
* Global Header Component dropdown button
*/
Expand Down

0 comments on commit 8a0b57f

Please sign in to comment.