Fix links on the header toolbar
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -1045,6 +1045,8 @@ export interface HeaderProps {
|
||||
tabs?: HeaderTab[];
|
||||
// (undocumented)
|
||||
title?: string;
|
||||
// (undocumented)
|
||||
titleLink?: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -230,6 +230,7 @@ export const WithEverything: Story = {
|
||||
menuItems,
|
||||
breadcrumbs,
|
||||
tabs,
|
||||
titleLink: '/',
|
||||
},
|
||||
decorators: layoutDecorator,
|
||||
render: args => (
|
||||
|
||||
@@ -32,7 +32,16 @@ declare module 'react-aria-components' {
|
||||
* @public
|
||||
*/
|
||||
export const Header = (props: HeaderProps) => {
|
||||
const { tabs, icon, title, menuItems, breadcrumbs, customActions } = props;
|
||||
const {
|
||||
tabs,
|
||||
icon,
|
||||
title,
|
||||
titleLink,
|
||||
menuItems,
|
||||
breadcrumbs,
|
||||
customActions,
|
||||
onTabSelectionChange,
|
||||
} = props;
|
||||
|
||||
const { classNames } = useStyles('Header');
|
||||
|
||||
@@ -43,6 +52,7 @@ export const Header = (props: HeaderProps) => {
|
||||
<HeaderToolbar
|
||||
icon={icon}
|
||||
title={title}
|
||||
titleLink={titleLink}
|
||||
menuItems={menuItems}
|
||||
breadcrumbs={breadcrumbs}
|
||||
customActions={customActions}
|
||||
@@ -50,7 +60,7 @@ export const Header = (props: HeaderProps) => {
|
||||
/>
|
||||
{tabs && (
|
||||
<div className={classNames.tabsWrapper}>
|
||||
<Tabs onSelectionChange={props.onTabSelectionChange}>
|
||||
<Tabs onSelectionChange={onTabSelectionChange}>
|
||||
<TabList>
|
||||
{tabs?.map(tab => (
|
||||
<Tab key={tab.id} id={tab.id} href={tab.href}>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Link } from 'react-aria-components';
|
||||
import { Link, RouterProvider } from 'react-aria-components';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
import { useRef, useState, useEffect } from 'react';
|
||||
import { RiArrowRightSLine, RiMore2Line, RiShapesLine } from '@remixicon/react';
|
||||
@@ -23,6 +23,7 @@ import { ButtonIcon } from '../ButtonIcon';
|
||||
import { Menu } from '../Menu';
|
||||
import { Text } from '../Text';
|
||||
import { motion, useScroll, useTransform } from 'motion/react';
|
||||
import { useNavigate, useHref } from 'react-router-dom';
|
||||
|
||||
/**
|
||||
* A component that renders a toolbar.
|
||||
@@ -30,9 +31,17 @@ import { motion, useScroll, useTransform } from 'motion/react';
|
||||
* @internal
|
||||
*/
|
||||
export const HeaderToolbar = (props: HeaderToolbarProps) => {
|
||||
const { icon, title, menuItems, breadcrumbs, customActions, hasTabs } = props;
|
||||
const {
|
||||
icon,
|
||||
title,
|
||||
titleLink,
|
||||
menuItems,
|
||||
breadcrumbs,
|
||||
customActions,
|
||||
hasTabs,
|
||||
} = props;
|
||||
const { classNames } = useStyles('Header');
|
||||
|
||||
let navigate = useNavigate();
|
||||
const { scrollY } = useScroll();
|
||||
const breadcrumbOpacity = useTransform(scrollY, [80, 120], [0, 1]);
|
||||
|
||||
@@ -87,80 +96,91 @@ export const HeaderToolbar = (props: HeaderToolbarProps) => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const titleContent = (
|
||||
<>
|
||||
<div className={classNames.toolbarIcon}>{icon || <RiShapesLine />}</div>
|
||||
<Text variant="body">{title || 'Your plugin'}</Text>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classNames.toolbar} data-has-tabs={hasTabs}>
|
||||
<div className={classNames.toolbarWrapper} ref={toolbarWrapperRef}>
|
||||
<div className={classNames.toolbarContent} ref={toolbarContentRef}>
|
||||
<div className={classNames.toolbarName}>
|
||||
<div className={classNames.toolbarIcon}>
|
||||
{icon || <RiShapesLine />}
|
||||
</div>
|
||||
<Text variant="body">{title || 'Your plugin'}</Text>
|
||||
<RouterProvider navigate={navigate} useHref={useHref}>
|
||||
{' '}
|
||||
<div className={classNames.toolbar} data-has-tabs={hasTabs}>
|
||||
<div className={classNames.toolbarWrapper} ref={toolbarWrapperRef}>
|
||||
<div className={classNames.toolbarContent} ref={toolbarContentRef}>
|
||||
{titleLink ? (
|
||||
<Link className={classNames.toolbarName} href={titleLink}>
|
||||
{titleContent}
|
||||
</Link>
|
||||
) : (
|
||||
<div className={classNames.toolbarName}>{titleContent}</div>
|
||||
)}
|
||||
{breadcrumbs && (
|
||||
<motion.div
|
||||
className={classNames.breadcrumbs}
|
||||
style={{
|
||||
opacity: breadcrumbOpacity,
|
||||
visibility: showBreadcrumbs ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
<RiArrowRightSLine
|
||||
size={16}
|
||||
className={classNames.breadcrumbSeparator}
|
||||
/>
|
||||
{breadcrumbs.map((breadcrumb, index) => (
|
||||
<div key={breadcrumb.label} className={classNames.breadcrumb}>
|
||||
<Link
|
||||
href={breadcrumb.href}
|
||||
className={classNames.breadcrumbLink}
|
||||
data-active={index === breadcrumbs.length - 1}
|
||||
>
|
||||
{breadcrumb.label}
|
||||
</Link>
|
||||
{index < breadcrumbs.length - 1 && (
|
||||
<RiArrowRightSLine
|
||||
size={16}
|
||||
className={classNames.breadcrumbSeparator}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
{breadcrumbs && (
|
||||
<motion.div
|
||||
className={classNames.breadcrumbs}
|
||||
style={{
|
||||
opacity: breadcrumbOpacity,
|
||||
visibility: showBreadcrumbs ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
<RiArrowRightSLine
|
||||
size={16}
|
||||
className={classNames.breadcrumbSeparator}
|
||||
/>
|
||||
{breadcrumbs.map((breadcrumb, index) => (
|
||||
<div key={breadcrumb.label} className={classNames.breadcrumb}>
|
||||
<Link
|
||||
href={breadcrumb.href}
|
||||
className={classNames.breadcrumbLink}
|
||||
data-active={index === breadcrumbs.length - 1}
|
||||
>
|
||||
{breadcrumb.label}
|
||||
</Link>
|
||||
{index < breadcrumbs.length - 1 && (
|
||||
<RiArrowRightSLine
|
||||
size={16}
|
||||
className={classNames.breadcrumbSeparator}
|
||||
<div className={classNames.toolbarControls} ref={toolbarControlsRef}>
|
||||
{customActions}
|
||||
{menuItems && (
|
||||
<Menu.Root>
|
||||
<Menu.Trigger
|
||||
render={props => (
|
||||
<ButtonIcon
|
||||
size="small"
|
||||
icon={<RiMore2Line />}
|
||||
variant="tertiary"
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
<div className={classNames.toolbarControls} ref={toolbarControlsRef}>
|
||||
{customActions}
|
||||
{menuItems && (
|
||||
<Menu.Root>
|
||||
<Menu.Trigger
|
||||
render={props => (
|
||||
<ButtonIcon
|
||||
size="small"
|
||||
icon={<RiMore2Line />}
|
||||
variant="tertiary"
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner sideOffset={4} align="end">
|
||||
<Menu.Popup>
|
||||
{menuItems.map(option => (
|
||||
<Menu.Item
|
||||
key={option.value}
|
||||
onClick={() => option.onClick?.()}
|
||||
>
|
||||
{option.label}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>
|
||||
</Menu.Root>
|
||||
)}
|
||||
/>
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner sideOffset={4} align="end">
|
||||
<Menu.Popup>
|
||||
{menuItems.map(option => (
|
||||
<Menu.Item
|
||||
key={option.value}
|
||||
onClick={() => option.onClick?.()}
|
||||
>
|
||||
{option.label}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>
|
||||
</Menu.Root>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RouterProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ import { TabsProps } from 'react-aria-components';
|
||||
export interface HeaderProps {
|
||||
icon?: React.ReactNode;
|
||||
title?: string;
|
||||
titleLink?: string;
|
||||
breadcrumbs?: HeaderBreadcrumb[];
|
||||
customActions?: React.ReactNode;
|
||||
menuItems?: HeaderMenuItem[];
|
||||
@@ -71,6 +72,7 @@ export interface HeaderBreadcrumb {
|
||||
export interface HeaderToolbarProps {
|
||||
icon?: HeaderProps['icon'];
|
||||
title?: HeaderProps['title'];
|
||||
titleLink?: HeaderProps['titleLink'];
|
||||
breadcrumbs?: HeaderProps['breadcrumbs'];
|
||||
customActions?: HeaderProps['customActions'];
|
||||
menuItems?: HeaderProps['menuItems'];
|
||||
|
||||
Reference in New Issue
Block a user