Style improvements on PluginHeader
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/ui': patch
|
||||
---
|
||||
|
||||
Merged the internal `PluginHeaderToolbar` component into `PluginHeader`, removing the separate component and its associated types (`PluginHeaderToolbarOwnProps`, `PluginHeaderToolbarProps`) and definition (`PluginHeaderToolbarDefinition`). This is an internal refactor with no changes to the public API of `PluginHeader`.
|
||||
|
||||
**Affected components:** PluginHeader
|
||||
@@ -183,26 +183,16 @@
|
||||
font-weight: var(--bui-font-weight-regular);
|
||||
}
|
||||
|
||||
.bui-HeaderToolbar {
|
||||
padding-top: var(--bui-space-2);
|
||||
padding-inline: var(--bui-space-2);
|
||||
}
|
||||
|
||||
.bui-HeaderToolbarWrapper {
|
||||
border-radius: var(--bui-radius-3);
|
||||
padding-inline: var(--bui-space-3);
|
||||
.bui-PluginHeaderToolbarWrapper {
|
||||
padding: 0;
|
||||
border: none;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.bui-HeaderToolbarControls {
|
||||
right: calc(var(--bui-space-3) - 1px);
|
||||
}
|
||||
|
||||
.bui-HeaderTabsWrapper {
|
||||
margin-top: var(--bui-space-2);
|
||||
margin-inline: var(--bui-space-2);
|
||||
border-radius: var(--bui-radius-3);
|
||||
padding-inline: var(--bui-space-1);
|
||||
.bui-PluginHeaderTabsWrapper {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-left: -8px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -1745,7 +1745,13 @@ export const PluginHeaderDefinition: {
|
||||
};
|
||||
readonly classNames: {
|
||||
readonly root: 'bui-PluginHeader';
|
||||
readonly tabsWrapper: 'bui-PluginHeaderTabsWrapper';
|
||||
readonly toolbar: 'bui-PluginHeaderToolbar';
|
||||
readonly toolbarWrapper: 'bui-PluginHeaderToolbarWrapper';
|
||||
readonly toolbarContent: 'bui-PluginHeaderToolbarContent';
|
||||
readonly toolbarControls: 'bui-PluginHeaderToolbarControls';
|
||||
readonly toolbarIcon: 'bui-PluginHeaderToolbarIcon';
|
||||
readonly toolbarName: 'bui-PluginHeaderToolbarName';
|
||||
readonly tabs: 'bui-PluginHeaderTabsWrapper';
|
||||
};
|
||||
readonly propDefs: {
|
||||
readonly icon: {};
|
||||
|
||||
@@ -17,26 +17,7 @@
|
||||
@layer tokens, base, components, utilities;
|
||||
|
||||
@layer components {
|
||||
.bui-PluginHeader {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bui-PluginHeaderToolbar {
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
height: 16px;
|
||||
background-color: var(--bui-bg-app);
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.bui-PluginHeaderToolbarWrapper {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
@@ -77,10 +58,6 @@
|
||||
}
|
||||
|
||||
.bui-PluginHeaderToolbarControls {
|
||||
position: absolute;
|
||||
right: var(--bui-space-5);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
@@ -15,13 +15,15 @@
|
||||
*/
|
||||
|
||||
import type { PluginHeaderProps } from './types';
|
||||
import { PluginHeaderToolbar } from './PluginHeaderToolbar';
|
||||
import { Tabs, TabList, Tab } from '../Tabs';
|
||||
import { useDefinition } from '../../hooks/useDefinition';
|
||||
import { PluginHeaderDefinition } from './definition';
|
||||
import { type NavigateOptions } from 'react-router-dom';
|
||||
import { useRef } from 'react';
|
||||
import { useIsomorphicLayoutEffect } from '../../hooks/useIsomorphicLayoutEffect';
|
||||
import { Link } from 'react-aria-components';
|
||||
import { RiShapesLine } from '@remixicon/react';
|
||||
import { Text } from '../Text';
|
||||
|
||||
declare module 'react-aria-components' {
|
||||
interface RouterConfig {
|
||||
@@ -49,6 +51,9 @@ export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
|
||||
const hasTabs = tabs && tabs.length > 0;
|
||||
const headerRef = useRef<HTMLElement>(null);
|
||||
const toolbarWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const toolbarContentRef = useRef<HTMLDivElement>(null);
|
||||
const toolbarControlsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const el = headerRef.current;
|
||||
@@ -82,17 +87,35 @@ export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const titleContent = (
|
||||
<>
|
||||
<div className={classes.toolbarIcon}>{icon || <RiShapesLine />}</div>
|
||||
<Text variant="body-medium">{title || 'Your plugin'}</Text>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<header ref={headerRef} className={classes.root}>
|
||||
<PluginHeaderToolbar
|
||||
icon={icon}
|
||||
title={title}
|
||||
titleLink={titleLink}
|
||||
customActions={customActions}
|
||||
hasTabs={hasTabs}
|
||||
/>
|
||||
<div className={classes.toolbar} data-has-tabs={hasTabs}>
|
||||
<div className={classes.toolbarWrapper} ref={toolbarWrapperRef}>
|
||||
<div className={classes.toolbarContent} ref={toolbarContentRef}>
|
||||
<Text as="h1" variant="body-medium">
|
||||
{titleLink ? (
|
||||
<Link className={classes.toolbarName} href={titleLink}>
|
||||
{titleContent}
|
||||
</Link>
|
||||
) : (
|
||||
<div className={classes.toolbarName}>{titleContent}</div>
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
<div className={classes.toolbarControls} ref={toolbarControlsRef}>
|
||||
{customActions}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{tabs && (
|
||||
<div className={classes.tabsWrapper}>
|
||||
<div className={classes.tabs}>
|
||||
<Tabs onSelectionChange={onTabSelectionChange}>
|
||||
<TabList>
|
||||
{tabs?.map(tab => (
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* 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 { Link } from 'react-aria-components';
|
||||
import { useDefinition } from '../../hooks/useDefinition';
|
||||
import { PluginHeaderToolbarDefinition } from './definition';
|
||||
import { useRef } from 'react';
|
||||
import { RiShapesLine } from '@remixicon/react';
|
||||
import type { PluginHeaderToolbarProps } from './types';
|
||||
import { Text } from '../Text';
|
||||
|
||||
/**
|
||||
* A component that renders the toolbar section of a plugin header.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const PluginHeaderToolbar = (props: PluginHeaderToolbarProps) => {
|
||||
const { ownProps } = useDefinition(PluginHeaderToolbarDefinition, props);
|
||||
const { classes, icon, title, titleLink, customActions, hasTabs } = ownProps;
|
||||
|
||||
// Refs for collision detection
|
||||
const toolbarWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const toolbarContentRef = useRef<HTMLDivElement>(null);
|
||||
const toolbarControlsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const titleContent = (
|
||||
<>
|
||||
<div className={classes.icon}>{icon || <RiShapesLine />}</div>
|
||||
<Text variant="body-medium">{title || 'Your plugin'}</Text>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classes.root} data-has-tabs={hasTabs}>
|
||||
<div className={classes.wrapper} ref={toolbarWrapperRef}>
|
||||
<div className={classes.content} ref={toolbarContentRef}>
|
||||
<Text as="h1" variant="body-medium">
|
||||
{titleLink ? (
|
||||
<Link className={classes.name} href={titleLink}>
|
||||
{titleContent}
|
||||
</Link>
|
||||
) : (
|
||||
<div className={classes.name}>{titleContent}</div>
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
<div className={classes.controls} ref={toolbarControlsRef}>
|
||||
{customActions}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
|
||||
import { defineComponent } from '../../hooks/useDefinition';
|
||||
import type {
|
||||
PluginHeaderOwnProps,
|
||||
PluginHeaderToolbarOwnProps,
|
||||
} from './types';
|
||||
import type { PluginHeaderOwnProps } from './types';
|
||||
import styles from './PluginHeader.module.css';
|
||||
|
||||
/**
|
||||
@@ -29,7 +26,13 @@ export const PluginHeaderDefinition = defineComponent<PluginHeaderOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-PluginHeader',
|
||||
tabsWrapper: 'bui-PluginHeaderTabsWrapper',
|
||||
toolbar: 'bui-PluginHeaderToolbar',
|
||||
toolbarWrapper: 'bui-PluginHeaderToolbarWrapper',
|
||||
toolbarContent: 'bui-PluginHeaderToolbarContent',
|
||||
toolbarControls: 'bui-PluginHeaderToolbarControls',
|
||||
toolbarIcon: 'bui-PluginHeaderToolbarIcon',
|
||||
toolbarName: 'bui-PluginHeaderToolbarName',
|
||||
tabs: 'bui-PluginHeaderTabsWrapper',
|
||||
},
|
||||
propDefs: {
|
||||
icon: {},
|
||||
@@ -41,28 +44,3 @@ export const PluginHeaderDefinition = defineComponent<PluginHeaderOwnProps>()({
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Component definition for PluginHeaderToolbar
|
||||
* @internal
|
||||
*/
|
||||
export const PluginHeaderToolbarDefinition =
|
||||
defineComponent<PluginHeaderToolbarOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-PluginHeaderToolbar',
|
||||
wrapper: 'bui-PluginHeaderToolbarWrapper',
|
||||
content: 'bui-PluginHeaderToolbarContent',
|
||||
controls: 'bui-PluginHeaderToolbarControls',
|
||||
icon: 'bui-PluginHeaderToolbarIcon',
|
||||
name: 'bui-PluginHeaderToolbarName',
|
||||
},
|
||||
propDefs: {
|
||||
icon: {},
|
||||
title: {},
|
||||
titleLink: {},
|
||||
customActions: {},
|
||||
hasTabs: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -55,24 +55,3 @@ export interface HeaderTab {
|
||||
*/
|
||||
matchStrategy?: TabMatchStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Own props for the PluginHeaderToolbar component.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface PluginHeaderToolbarOwnProps {
|
||||
icon?: PluginHeaderOwnProps['icon'];
|
||||
title?: PluginHeaderOwnProps['title'];
|
||||
titleLink?: PluginHeaderOwnProps['titleLink'];
|
||||
customActions?: PluginHeaderOwnProps['customActions'];
|
||||
hasTabs?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for the PluginHeaderToolbar component.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface PluginHeaderToolbarProps extends PluginHeaderToolbarOwnProps {}
|
||||
|
||||
Reference in New Issue
Block a user