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'); + }); +});