Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/layout-header-back-button.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cube-dev/ui-kit": minor
---

Added `onBack` prop to `Layout.Header` component. When provided, a back button with arrow icon is rendered to the left of the title, allowing users to navigate back from the current page.
24 changes: 24 additions & 0 deletions src/components/content/Layout/Layout.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ A semantic page header with title, breadcrumbs, subtitle, and action areas.
| subtitle | `ReactNode` | - | Text below the title |
| suffix | `ReactNode` | - | Content next to the title |
| extra | `ReactNode` | - | Content on the right side |
| onBack | `() => void` | - | Callback for the back button. When provided, a back arrow button appears to the left of the title. |

**Sub-elements:**
- `Back` - Back button container (visible when `onBack` is provided)
- `Breadcrumbs` - Navigation path container
- `Title` - Main heading element
- `Suffix` - Content adjacent to title
Expand Down Expand Up @@ -431,6 +433,28 @@ A variant of Layout that enables CSS Grid for the content area.
</Layout>
```

### With Back Button

<Story of={LayoutStories.WithBackButton} />

```jsx
<Layout height="100dvh">
<Layout.Header
title="Report Details"
onBack={() => navigate(-1)}
extra={
<Space>
<Button>Export</Button>
<Button type="primary">Edit</Button>
</Space>
}
/>
<Layout.Content>
<Text>Page content with a back button in the header</Text>
</Layout.Content>
</Layout>
```

### Resizable Side Panel

<Story of={LayoutStories.ResizablePanel} />
Expand Down
20 changes: 20 additions & 0 deletions src/components/content/Layout/Layout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,26 @@ export const WithBreadcrumbs: Story = {
),
};

export const WithBackButton: Story = {
render: () => (
<Layout height="100dvh">
<Layout.Header
title="Report Details"
extra={
<Space>
<Button>Export</Button>
<Button type="primary">Edit</Button>
</Space>
}
onBack={() => console.log('Back pressed')}
/>
<Layout.Content>
<Text>Page content with a back button in the header</Text>
</Layout.Content>
</Layout>
),
};

export const WithSidePanel: Story = {
render: function WithSidePanelStory() {
const [isPanelOpen, setIsPanelOpen] = useState(true);
Expand Down
31 changes: 27 additions & 4 deletions src/components/content/Layout/LayoutHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IconArrowLeft } from '@tabler/icons-react';
import {
ForwardedRef,
forwardRef,
Expand All @@ -10,6 +11,7 @@ import {

import { SlashIcon } from '../../../icons/SlashIcon';
import { tasty } from '../../../tasty';
import { Button } from '../../actions/Button/Button';
import { Link } from '../../actions/Link/Link';
import { useAutoTooltip } from '../use-auto-tooltip';

Expand All @@ -29,16 +31,24 @@ const HeaderElement = tasty(LayoutContent, {
$: '>',
display: 'grid',
gridTemplate: `
"breadcrumbs breadcrumbs breadcrumbs" auto
"title suffix extra" 1fr
"subtitle subtitle extra" auto
/ max-content 1fr minmax(0, auto)
"breadcrumbs breadcrumbs breadcrumbs breadcrumbs" auto
"back title suffix extra" 1fr
".. subtitle subtitle extra" auto
/ auto max-content 1fr minmax(0, auto)
`,
gap: 0,
placeContent: 'stretch',
placeItems: 'center stretch',
},

Back: {
$: '> Inner >',
gridArea: 'back',
display: 'flex',
placeItems: 'center',
margin: '.5x right',
},

Breadcrumbs: {
$: '> Inner >',
gridArea: 'breadcrumbs',
Expand Down Expand Up @@ -111,6 +121,8 @@ export interface CubeLayoutHeaderProps extends CubeLayoutContentProps {
* Uses Link component which integrates with the navigation provider.
*/
breadcrumbs?: Array<[label: string, href: string]>;
/** Callback for the back button. When provided, a back arrow button is rendered to the left of the title. */
onBack?: () => void;
}

function LayoutHeader(
Expand All @@ -124,6 +136,7 @@ function LayoutHeader(
extra,
subtitle,
breadcrumbs,
onBack,
scrollbar = 'tiny',
children,
mods,
Expand Down Expand Up @@ -181,6 +194,16 @@ function LayoutHeader(
scrollbar={scrollbar}
>
{renderBreadcrumbs()}
{onBack && (
<div data-element="Back">
<Button
type="neutral"
icon={<IconArrowLeft />}
aria-label="Go back"
onPress={onBack}
/>
</div>
)}
{renderWithTooltip(renderTitle, 'bottom')}
{suffix && <div data-element="Suffix">{suffix}</div>}
{extra && <div data-element="Extra">{extra}</div>}
Expand Down
Loading