From feab9602331ba1beb21238645040e3e3c90438d3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 26 May 2026 12:52:15 +0000
Subject: [PATCH 1/2] Initial plan
From 82a1f76cb61f773234474e56a7f02a42297d979f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 26 May 2026 13:00:52 +0000
Subject: [PATCH 2/2] Add up/down fan-out directions for ToolbarFanOutItem
Agent-Logs-Url: https://github.com/Cratis/Components/sessions/b46fc4b1-b1f2-4aa5-9d4d-ce0c2ba074f8
Co-authored-by: einari <134365+einari@users.noreply.github.com>
---
Documentation/Toolbar/fan-out.md | 12 ++++++
Source/Toolbar/Toolbar.css | 17 ++++++++
Source/Toolbar/Toolbar.stories.tsx | 20 +++++++++
Source/Toolbar/ToolbarFanOutItem.tsx | 2 +-
.../and_item_is_rendered.ts | 41 +++++++++++++++++++
5 files changed, 91 insertions(+), 1 deletion(-)
create mode 100644 Source/Toolbar/for_ToolbarFanOutItem/when_direction_is_set/and_item_is_rendered.ts
diff --git a/Documentation/Toolbar/fan-out.md b/Documentation/Toolbar/fan-out.md
index 49d46f0..e0b8b0c 100644
--- a/Documentation/Toolbar/fan-out.md
+++ b/Documentation/Toolbar/fan-out.md
@@ -21,6 +21,18 @@ By default the panel fans out to the right. Use `fanOutDirection='left'` when th
```
+You can also fan out vertically:
+
+```tsx
+
+ ...
+
+
+
+ ...
+
+```
+
## ReactNode Icons
Like `ToolbarButton`, the `icon` prop accepts a `string | ReactNode`. Pass any React element as the trigger icon:
diff --git a/Source/Toolbar/Toolbar.css b/Source/Toolbar/Toolbar.css
index 87c43fb..3b05877 100644
--- a/Source/Toolbar/Toolbar.css
+++ b/Source/Toolbar/Toolbar.css
@@ -163,6 +163,23 @@
clip-path: inset(0 0 0 100% round 1rem);
}
+.toolbar-fanout-panel--up {
+ top: auto;
+ right: auto;
+ bottom: calc(100% + 0.5rem);
+ left: 50%;
+ transform: translateX(-50%);
+ clip-path: inset(100% 0 0 0 round 1rem);
+}
+
+.toolbar-fanout-panel--down {
+ top: calc(100% + 0.5rem);
+ right: auto;
+ left: 50%;
+ transform: translateX(-50%);
+ clip-path: inset(0 0 100% 0 round 1rem);
+}
+
/* Expanded state — fully visible, pointer events restored */
.toolbar-fanout-panel--visible {
clip-path: inset(0 0 0 0 round 1rem);
diff --git a/Source/Toolbar/Toolbar.stories.tsx b/Source/Toolbar/Toolbar.stories.tsx
index 88fdfb6..d47e9a8 100644
--- a/Source/Toolbar/Toolbar.stories.tsx
+++ b/Source/Toolbar/Toolbar.stories.tsx
@@ -318,6 +318,26 @@ export const WithFanOut: Story = {
},
};
+/** Demonstrates a {@link ToolbarFanOutItem} that fans out downwards. */
+export const WithFanOutDown: Story = {
+ render: () => (
+
+
+
+
+
+
+
+
+
+ ),
+};
+
/** Demonstrates a folder with a single nested button. */
export const WithFolderOneButton: Story = {
render: () => (
diff --git a/Source/Toolbar/ToolbarFanOutItem.tsx b/Source/Toolbar/ToolbarFanOutItem.tsx
index aecba6c..2bd591a 100644
--- a/Source/Toolbar/ToolbarFanOutItem.tsx
+++ b/Source/Toolbar/ToolbarFanOutItem.tsx
@@ -19,7 +19,7 @@ export interface ToolbarFanOutItemProps {
tooltipPosition?: TooltipPosition;
/** Direction the panel fans out from the trigger button (default: 'right'). */
- fanOutDirection?: 'right' | 'left';
+ fanOutDirection?: 'right' | 'left' | 'up' | 'down';
/** The toolbar items to render inside the fan-out panel. */
children: ReactNode;
diff --git a/Source/Toolbar/for_ToolbarFanOutItem/when_direction_is_set/and_item_is_rendered.ts b/Source/Toolbar/for_ToolbarFanOutItem/when_direction_is_set/and_item_is_rendered.ts
new file mode 100644
index 0000000..17e2300
--- /dev/null
+++ b/Source/Toolbar/for_ToolbarFanOutItem/when_direction_is_set/and_item_is_rendered.ts
@@ -0,0 +1,41 @@
+// Copyright (c) Cratis. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+import React from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+import { vi } from 'vitest';
+import { ToolbarFanOutItem } from '../../ToolbarFanOutItem';
+
+vi.mock('../../Common/Tooltip', () => ({
+ Tooltip: (props: { children?: React.ReactNode }) => React.createElement('div', null, props.children),
+}));
+
+describe('when ToolbarFanOutItem direction is set and item is rendered', () => {
+ const render = (fanOutDirection?: 'left' | 'right' | 'up' | 'down') =>
+ renderToStaticMarkup(
+ React.createElement(
+ ToolbarFanOutItem,
+ {
+ icon: 'pi pi-th-large',
+ tooltip: 'Shapes',
+ fanOutDirection,
+ },
+ React.createElement('div', null, 'Child'),
+ ),
+ );
+
+ it('should_default_to_right_direction', () => {
+ const html = render();
+ html.should.include('toolbar-fanout-panel--right');
+ });
+
+ it('should_support_up_direction', () => {
+ const html = render('up');
+ html.should.include('toolbar-fanout-panel--up');
+ });
+
+ it('should_support_down_direction', () => {
+ const html = render('down');
+ html.should.include('toolbar-fanout-panel--down');
+ });
+});